#Imports
import pprint as p
import numpy as np

#Variables
value = ""
destruction = True
skip = False
count = 0

#Functions
def annihilates(str_1, str_2):
    output = False
    temp = str_1.swapcase()
    if temp == str_2: output = True
    return output

#Create list from input.txt file
folder_path = "D:/_SCRIPTING/_ScriptProjects/25DaysTillChristmas-GITHUB/Day_05/"
text_file = open(folder_path + "input.txt", "r")
input_str = text_file.read()
text_file.close()
value = input_str

#While loop to test if any more can be destroyed
while destruction:
    #Set some helpful variables
    count += 1
    temp_str = ""
    skip = False
    end_str = value[len(value)-1]
    destruction = False
    #Itterate through text
    for i in range( len(value) - 1 ):
        if skip:
            skip = False
        else:
            str_1 = value[i]
            str_2 = value[i + 1]
            boom = annihilates(str_1, str_2)
            if boom:
                skip = True
                destruction = True
                if i == len(value)-2: end_str = ""
            else:
                temp_str += str_1
                temp_str_2 = str_2
    value = temp_str + end_str

#Print out value
print("amount in original list: " + str(len(input_str)))
print("amount in new list: " + str(len(value)))


# encoding: utf-8

"""Web-based REPL shell and interactive debugger extension."""

# ## Imports

from __future__ import unicode_literals

from webob.exc import HTTPNotFound
from backlash import DebuggedApplication

# ## Module Globals

log = __import__('logging').getLogger(__name__)

# ## Controller Endpoint Utility

class Console(object):
	"""Attach a console to your web application at an arbitrary location."""

	__slots__ = ('debugger', 'request')

	def __init__(self, context):
		self.debugger = context.get('debugger', None)
		self.request = context.request

	def __call__(self, *args, **kw):
		if not self.debugger:
			raise HTTPNotFound()

		return self.debugger.display_console(self.request)

# ## Extension

class DebugExtension(object):
	"""Enable an interactive exception debugger and interactive console.

	Possible configuration includes:

		* `path` -- the path to the interactive console, defaults to: `/__console__`
		* `verbose` -- show ordinarily hidden stack frames, defaults to: `False`
	"""

	__slots__ = ('path', 'verbose')

	provides = ['debugger', 'console']

	def __init__(self, path="/__console__", verbose=False):
		if __debug__:
			log.debug("Initializing debugger extension.")

		self.path = path
		self.verbose = verbose

		super(DebugExtension, self).__init__()

	def init_console(self):
		"""Add variables to the console context."""
		return dict()

	def init_debugger(self, environ):
		"""Add variables to the debugger context."""
		return dict(context=environ.get('context'))

	def __call__(self, context, app):
		"""Executed to wrap the application in middleware.

		The first argument is the application context, not request context.

		Accepts a WSGI application as the second argument and must likewise return a WSGI app.
		"""

		if __debug__:
			log.debug("Wrapping application in debugger middleware.")

		app = DebuggedApplication(
				app,
				evalex = __debug__,  # In production mode, this is a security no-no.
				show_hidden_frames = self.verbose,
				console_init_func = self.init_console,
				context_injectors = [self.init_debugger],
			)

		context.debugger = app

		return app


# -*- coding: utf-8 -*-
"""
Created on Fri Jan 24 2020

@author: Marcus Futterlieb
"""

import os
import csv
#from os.path import isfile, join
from pandas import DataFrame
import pandas

def libraryParser(path):
    onlyfiles = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f))]
#    for item in onlyfiles:
#        print(item);
    print(onlyfiles)

def rowCount(file):
    with open(file, 'r') as t2:
        reader = csv.reader(t2, delimiter=",")
        data = list(reader)
        rowCount = len(data)
        # print(rowCount);
        # print('rowcount OK');
        if (rowCount != 32):
            print("Error: issue with rowcount")
            return (999)
        else:
            return (rowCount)

def writeToCSV (stockName, stockDates, stockOpen,stockHigh ,stockLow, stockClose, stockTradedUnits, stockVolume,
                   stockDivDate, stockDivValue, stockDivYield, stockPerformanceDate,
                   stockPerformanceCurrency, stockPerformancePercent):
    #try to create the library archive
    try:
        os.mkdir("./library")
    except OSError as e:
       print("writeToCSV: Directory (./library) exists")

    bundledInformation1 = {'stockDates': stockDates, 'stockOpen': stockOpen, 'stockHigh': stockHigh,
                           'stockLow': stockLow,
                           'stockClose': stockClose, 'stockTradedUnits': stockTradedUnits, 'stockVolume': stockVolume}
    bundledInformation2 = {'stockDivDate': stockDivDate, 'stockDivValue': stockDivValue, 'stockDivYield': stockDivYield}
    bundledInformation3 = {'stockPerformanceDate': stockPerformanceDate,
                           'stockPerformanceCurrency': stockPerformanceCurrency,
                           'stockPerformancePercent': stockPerformancePercent}

    df1 = DataFrame(bundledInformation1, columns=['stockDates', 'stockOpen', 'stockHigh', 'stockLow', 'stockClose',
                                                  'stockTradedUnits', 'stockVolume'])
    df2 = DataFrame(bundledInformation2, columns=['stockDivDate', 'stockDivValue',
                                                  'stockDivYield'])
    df3 = DataFrame(bundledInformation3, columns=['stockPerformanceDate', 'stockPerformanceCurrency',
                                                  'stockPerformancePercent'])
    export_csv1 = df1.to_csv(r'./library/' + stockName + '__hist__new.csv', index=None, header=True)
    export_csv2 = df2.to_csv(r'./library/' + stockName + '__divi__new.csv', index=None, header=True)
    export_csv3 = df3.to_csv(r'./library/' + stockName + '__perf__new.csv', index=None, header=True)
    print ('writeToCSV: ', stockName, '__new has been written into your personal library')

def overviewUpdate (stockList):
    if not (os.path.exists('library/overview.csv')):
        print('overviewUpdate: overview does not exist --> creating ...')
        bundledInformation = {'stockName': stockList, 'prefValue': zerolistmaker(len(stockList))}
        df = DataFrame(bundledInformation, columns=['stockName', 'prefValue'])
        export_csv = df.to_csv(r'./library/overview.csv', index=None, header=True)
    else:
        updateOverview = False
        print('overviewUpdate: overview does exist --> updating ...')
        historicValues_old = pandas.read_csv('./library/overview.csv')
        stockList_old = historicValues_old['stockName']
        for cnt_new in range(0, len(stockList)):
            cnt_tmp = 0
            print('overviewUpdate: searching ', stockList[cnt_new])
            for cnt_old in range(0, len(stockList_old)):
                if (stockList_old.iloc[cnt_old]==stockList[cnt_new]):
                    print('overviewUpdate: found ', stockList[cnt_new])
                    break
                else:
                    cnt_tmp = cnt_tmp+1
                    #print('overviewUpdate: counter ', cnt_tmp, '  counterlimit ', len(stockList_old))
                    if (cnt_tmp>=len(stockList_old)):
                        print('overviewUpdate: NOT found ', stockList[cnt_new], ' --> appending...')
                        historicValues_old = historicValues_old.append([stockList[cnt_new], 0])
                        print('overviewUpdate: new dataframe: ', historicValues_old)
                        updateOverview = True

        if (updateOverview==True):
            print('overviewUpdate: new dataframe: ', historicValues_old)
            export_csv1 = historicValues_old.to_csv(r'./library/overview.csv', index=None, header=True)
            print('overviewUpdate: had to rewrite the overview.csv')
            # TODO --> test if this works

def zerolistmaker(n):
    listofzeros = [0] * n
    return listofzeros


from pre_proc import parse_digits
from sklearn.linear_model import LogisticRegression
from sklearn.cluster import KMeans
import numpy as np
import matplotlib.pyplot as plt

def show_digits(digits):
    for index, digits in enumerate(digits):
        plt.subplot(k // 10, 10, index + 1)
        plt.imshow(digits.reshape(8, 8), cmap="binary", interpolation="bilinear")
        plt.axis('off')
    plt.show()

if __name__ == "__main__":
    # Take 50 labelled instances
    X_train, X_test, y_train, y_test = parse_digits()
    n_labeled = 50
    log_reg = LogisticRegression(random_state=42)
    log_reg.fit(X_train[:n_labeled], y_train[:n_labeled])
    print(X_train[:n_labeled])
    print(y_train[:n_labeled])

    # Having few labelled instances to train on results in
    # a low accuracy
    print(log_reg.score(X_test, y_test))

    # We can improve on this by using clustering
    k = 50
    kmeans = KMeans(n_clusters=k, random_state=42)

    # Contains the distances from each digit (row) to
    # the centroid of all clusters (column)
    X_digits_dist = kmeans.fit_transform(X_train)

    # For each cluster, find the digit closest to the centroid
    representative_digit_idx = np.argmin(X_digits_dist, axis=0)
    X_representative_digits = X_train[representative_digit_idx]

    # We look at each representative digit and manually label them
    # show_digits(X_representative_digits)
    y_representative_digits = np.array([
                                        0, 1, 3, 2, 7, 6, 4, 6, 9, 5,
                                        1, 2, 9, 5, 2, 7, 8, 1, 8, 6,
                                        3, 2, 5, 4, 5, 4, 0, 3, 2, 6,
                                        1, 7, 7, 9, 1, 8, 6, 5, 4, 8,
                                        5, 3, 3, 6, 7, 9, 7, 8, 4, 9])

    # Therefore, instead of having 50 random labeled instances
    # we instead have instances which are representative of their cluster
    # This increases the accuracy.
    log_reg = LogisticRegression(random_state=42)
    log_reg.fit(X_representative_digits, y_representative_digits)
    print(log_reg.score(X_test, y_test))

    # It is possible to perform label propagation, where we
    # propagate the labels to all other instances in the cluster
    y_train_propagated = np.empty(len(X_train), dtype=np.int32)
    for i in range(k):
        y_train_propagated[kmeans.labels_ == i] = y_representative_digits[i]

    log_reg = LogisticRegression(random_state=42)
    log_reg.fit(X_train, y_train_propagated)
    print(log_reg.score(X_test, y_test))

    # An even better idea is to only propagate the label to
    # the 20% of instances that are closest to the centroid
    percentile_closest = 20
    X_cluster_dist = X_digits_dist[np.arange(len(X_train)), kmeans.labels_]

    for i in range(k):
        in_cluster = (kmeans.labels_ == i)
        cluster_dist = X_cluster_dist[in_cluster]
        cutoff_distance = np.percentile(cluster_dist, percentile_closest)
        above_cutoff = (X_cluster_dist > cutoff_distance)
        X_cluster_dist[in_cluster & above_cutoff] = -1

    partially_propagated = (X_cluster_dist != -1)
    X_train_partially_propagated = X_train[partially_propagated]
    y_train_partially_propagated = y_train_propagated[partially_propagated]

    log_reg = LogisticRegression(random_state=42)
    log_reg.fit(X_train_partially_propagated, y_train_partially_propagated)
    print(log_reg.score(X_test, y_test))


import numpy
import cv2

from denoise_algorithms.ADenoiser import *
# this code from https://github.com/wuqiyao20160118/
# Parameters initialization
params1 = {}
params1["Threshold_Hard3D"] = 2.7 * 40
params1["First_Match_threshold"] = 5000
params1["Step1_max_matched_cnt"] = 16
params1["Step1_Blk_Size"] = 8
params1["Step1_Blk_Step"] = 3
params1["Step1_Search_Step"] = 3
params1["Step1_Search_Window"] = 39

params1["Second_Match_threshold"] = 5000
params1["Step2_max_matched_cnt"] = 32
params1["Step2_Blk_Size"] = 8
params1["Step2_Blk_Step"] = 3
params1["Step2_Search_Step"] = 3
params1["Step2_Search_Window"] = 39
class BM3D(ADenoiser):
	def __init__(self, params=None):
		#params = params1.copy()
		if params is None:
			self.params = {}
			self.sigma = 40

			self.params["sigma"] = int(40)
			self.params["Threshold_Hard3D"] = 2.7 * self.sigma
			self.params["First_Match_threshold"] = 2500
			self.params["Step1_max_matched_cnt"] = 16
			self.params["Step1_Blk_Size"] = 8
			self.params["Step1_Blk_Step"] = 3
			self.params["Step1_Search_Step"] = 3
			self.params["Step1_Search_Window"] = 39

			self.params["Second_Match_threshold"] = 400
			self.params["Step2_max_matched_cnt"] = 32
			self.params["Step2_Blk_Size"] = 8
			self.params["Step2_Blk_Step"] = 3
			self.params["Step2_Search_Step"] = 3
			self.params["Step2_Search_Window"] = 39
		else:
			self.params = params
			self.params["sigma"] = int(40)
			self.params["First_Match_threshold"] = int(self.params["First_Match_threshold"])
			self.params["Step1_max_matched_cnt"] = int(self.params["Step1_max_matched_cnt"])
			self.params["Step1_Blk_Size"] = int(self.params["Step1_Blk_Size"] )
			self.params["Step1_Blk_Step"] = int(self.params["Step1_Blk_Step"])
			self.params["Step1_Search_Step"] = int(self.params["Step1_Search_Step"])
			self.params["Step1_Search_Window"] = int(self.params["Step1_Search_Window"] )

			self.params["Second_Match_threshold"] = int(self.params["Second_Match_threshold"])
			self.params["Step2_max_matched_cnt"] = int(self.params["Step2_max_matched_cnt"])
			self.params["Step2_Blk_Size"] = int(self.params["Step2_Blk_Size"] )
			self.params["Step2_Blk_Step"] = int(self.params["Step2_Blk_Step"] )
			self.params["Step2_Search_Step"] = int(self.params["Step2_Search_Step"])
			self.params["Step2_Search_Window"] = int(self.params["Step2_Search_Window"])

		ADenoiser.__init__(self,"BM3D", self.params)

	def get_name(self):
		return ADenoiser.get_name(self)

	def __Locate_blk(self,i, j, blk_step, block_size, width, height):
		if i * blk_step + block_size < width:
			point_x = i * blk_step
		else:
			point_x = width - block_size
		if j * blk_step + block_size < height:
			point_y = j * blk_step
		else:
			point_y = height - block_size
		blockPoint = numpy.array((point_x, point_y), dtype=int)
		return blockPoint

	def __Define_SearchWindow(self,img, BlockPoint, WindowSize, Blk_Size):
		"""
		:param img: input image
		:param BlockPoint: coordinate of the left-top corner of the block
		:param WindowSize: size of the search window
		:param Blk_Size:
		:return: left-top corner point of the search window
		"""
		point_x = BlockPoint[0]
		point_y = BlockPoint[1]
		# get four corner points
		x_min = point_x + Blk_Size / 2 - WindowSize / 2
		y_min = point_y + Blk_Size / 2 - WindowSize / 2
		x_max = x_min + WindowSize
		y_max = y_min + WindowSize
		# check whether the corner points have out of range
		if x_min < 0:
			x_min = 0
		elif x_max > img.shape[0]:
			x_min = img.shape[0] - WindowSize
		if y_min < 0:
			y_min = 0
		elif y_max > img.shape[0]:
			y_min = img.shape[0] - WindowSize
		return numpy.array((x_min, y_min), dtype=int)

	def __step1_fast_match(self, img, BlockPoint):
		x, y = BlockPoint
		blk_size = self.params["Step1_Blk_Size"]
		Search_Step = self.params["Step1_Search_Step"]
		Threshold = self.params["First_Match_threshold"]
		max_matched = self.params["Step1_max_matched_cnt"]
		window_size = self.params["Step1_Search_Window"]

		blk_positions = numpy.zeros((max_matched, 2), dtype=int)
		similar_blocks_3d = numpy.zeros((max_matched, blk_size, blk_size), dtype=float)
		image = img[x:x + blk_size, y:y + blk_size]
		dct_img = cv2.dct(image.astype(numpy.float64))
		window_location = self.__Define_SearchWindow(img, BlockPoint, window_size, blk_size)
		blk_num = int((window_size - blk_size) / Search_Step)
		window_x, window_y = window_location

		count = 0
		matched_blk_pos = numpy.zeros((blk_num ** 2, 2), dtype=int)
		matched_distance = numpy.zeros(blk_num ** 2, dtype=float)
		similar_blocks = numpy.zeros((blk_num ** 2, blk_size, blk_size), dtype=float)

		for i in range(blk_num):
			for j in range(blk_num):
				search_img = img[window_x:window_x + blk_size, window_y:window_y + blk_size]
				if search_img % 2 is not 0:
					continue
				dct_search_img = cv2.dct(search_img.astype(numpy.float64))
				distance = numpy.linalg.norm((dct_img - dct_search_img)) ** 2 / (blk_size ** 2)
				if 0 < distance < Threshold:
					matched_blk_pos[count] = numpy.array((window_x, window_y))
					matched_distance[count] = distance
					similar_blocks[count] = dct_search_img
					count += 1
				window_y += Search_Step
			window_x += Search_Step
			window_y = window_location[1]
		distance = matched_distance[:count]
		sort_index = distance.argsort()

		if count >= max_matched:
			count = max_matched
		else:
			count += 1  # add the template image

		similar_blocks_3d[0] = dct_img
		blk_positions[0] = numpy.array((x, y))
		for i in range(1, count):
			index = sort_index[i - 1]
			similar_blocks_3d[i] = similar_blocks[index]
			blk_positions[i] = matched_blk_pos[index]
		return similar_blocks_3d, blk_positions, count

	def __step1_3DFiltering(self, similar_blocks):
		nonzero_count = 0
		for i in range(similar_blocks.shape[1]):
			for j in range(similar_blocks.shape[2]):
				harr_img = cv2.dct(similar_blocks[:, i, j].astype(numpy.float64))
				harr_img[numpy.abs(harr_img) < self.params["Threshold_Hard3D"]] = 0
				nonzero_count += harr_img.nonzero()[0].size
				similar_blocks[:, i, j] = cv2.idct(harr_img)[0]
		return similar_blocks, nonzero_count

	def __integ_hardthreshold(self, similar_blocks, blk_positions, basic_img, weight_img, nonzero_count, matched_num,
							Kaiser=None):
		blk_shape = similar_blocks.shape
		if nonzero_count < 1:
			nonzero_count = 1
		block_wight = (1. / nonzero_count)  # * Kaiser
		for i in range(matched_num):
			point = blk_positions[i, :]
			temp_img = (1. / nonzero_count) * cv2.idct(similar_blocks[i, :, :])  # * Kaiser
			basic_img[point[0]:point[0] + blk_shape[1], point[1]:point[1] + blk_shape[2]] += temp_img
			weight_img[point[0]:point[0] + blk_shape[1], point[1]:point[1] + blk_shape[2]] += block_wight
		return basic_img, weight_img

	def __BM3D_step_1(self, img):
		width, height = img.shape
		block_size = self.params["Step1_Blk_Size"]
		blk_step = self.params["Step1_Blk_Step"]
		width_num = int((width - block_size) / blk_step)
		height_num = int((height - block_size) / blk_step)
		filtered_img = numpy.zeros(img.shape, dtype=float)
		filter_weight = numpy.zeros(img.shape, dtype=float)

		# K = numpy.kaiser(block_size, Beta_Kaiser)
		# m_Kaiser = numpy.matmul(K.T, K)  # construct a Kaiser window

		for i in range(width_num + 2):
			for j in range(height_num + 2):
				BlockPoint = self.__Locate_blk(i, j, blk_step, block_size, width, height)
				similar_blocks_3d, blk_positions, count = self.__step1_fast_match(img, BlockPoint)
				similar_blocks, nonzero_count = self.__step1_3DFiltering(similar_blocks_3d)
				filtered_img, filter_weight = self.__integ_hardthreshold(similar_blocks, blk_positions, filtered_img,
																  filter_weight, nonzero_count, count)
		filtered_img /= filter_weight
		filtered_img.astype(numpy.uint8)
		return filtered_img

	def __step2_fast_match(self, basic_img, img, BlockPoint):
		x, y = BlockPoint
		blk_size = self.params["Step2_Blk_Size"]
		Threshold = self.params["Second_Match_threshold"]
		Search_Step = self.params["Step2_Search_Step"]
		max_matched = self.params["Step2_max_matched_cnt"]
		window_size = self.params["Step2_Search_Window"]

		blk_positions = numpy.zeros((max_matched, 2), dtype=int)
		similar_blocks_3d = numpy.zeros((max_matched, blk_size, blk_size), dtype=float)
		basic_similar_blocks_3d = numpy.zeros((max_matched, blk_size, blk_size), dtype=float)

		basic_image = basic_img[x:x + blk_size, y:y + blk_size]
		basic_dct_img = cv2.dct(basic_image.astype(numpy.float64))
		image = img[x:x + blk_size, y:y + blk_size]
		dct_img = cv2.dct(image.astype(numpy.float64))

		window_location = self.__Define_SearchWindow(img, BlockPoint, window_size, blk_size)
		blk_num = int((window_size - blk_size) / Search_Step)
		window_x, window_y = window_location

		count = 0
		matched_blk_pos = numpy.zeros((blk_num ** 2, 2), dtype=int)
		matched_distance = numpy.zeros(blk_num ** 2, dtype=float)
		similar_blocks = numpy.zeros((blk_num ** 2, blk_size, blk_size), dtype=float)

		for i in range(blk_num):
			for j in range(blk_num):
				search_img = basic_img[window_x:window_x + blk_size, window_y:window_y + blk_size]
				if search_img % 2 is not 0:
					continue
				dct_search_img = cv2.dct(search_img.astype(numpy.float64))
				distance = numpy.linalg.norm((dct_img - dct_search_img)) ** 2 / (blk_size ** 2)

				if 0 < distance < Threshold:
					matched_blk_pos[count] = numpy.array((window_x, window_y))
					matched_distance[count] = distance
					similar_blocks[count] = dct_search_img
					count += 1
				window_y += Search_Step
			window_x += Search_Step
			window_y = window_location[1]
		distance = matched_distance[:count]
		sort_index = distance.argsort()

		if count >= max_matched:
			count = max_matched
		else:
			count += 1  # add the template image

		basic_similar_blocks_3d[0] = basic_dct_img
		similar_blocks_3d[0] = dct_img
		blk_positions[0] = numpy.array((x, y))
		for i in range(1, count):
			index = sort_index[i - 1]
			basic_similar_blocks_3d[i] = similar_blocks[index]
			blk_positions[i] = matched_blk_pos[index]

			x, y = blk_positions[i]
			#temp_noisy_img = noised_img[x:x + blk_size, y:y + blk_size]
			temp_noisy_img = img[x:x + blk_size, y:y + blk_size]
			similar_blocks_3d[i] = cv2.dct(temp_noisy_img.astype(numpy.float64))

		return basic_similar_blocks_3d, similar_blocks_3d, blk_positions, count

	def __step2_3DFiltering(self, similar_basic_blocks, similar_blocks):
		img_shape = similar_basic_blocks.shape
		Wiener_weight = numpy.zeros((img_shape[1], img_shape[2]), dtype=float)

		for i in range(img_shape[1]):
			for j in range(img_shape[2]):
				temp_vector = similar_basic_blocks[:, i, j]
				dct_temp = cv2.dct(temp_vector)
				norm2 = numpy.matmul(dct_temp.T, dct_temp)
				filter_weight = norm2 / (norm2 + self.params["sigma"] ** 2)
				if filter_weight != 0:
					Wiener_weight[i, j] = 1 / (filter_weight ** 2)
				# Wiener_weight[i, j] = 1 / (filter_weight**2 * self.sigma**2)
				temp_vector = similar_blocks[:, i, j]
				dct_temp = cv2.dct(temp_vector) * filter_weight
				similar_basic_blocks[:, i, j] = cv2.idct(dct_temp)[0]

		return similar_basic_blocks, Wiener_weight

	def __integ_Wiener(self, similar_blocks, Wiener_weight, blk_positions, basic_img, weight_img, matched_num):
		img_shape = similar_blocks.shape
		block_weight = Wiener_weight

		for i in range(matched_num):
			point = blk_positions[i]
			temp_img = block_weight * cv2.idct(similar_blocks[i, :, :])
			basic_img[point[0]:point[0] + img_shape[1], point[1]:point[1] + img_shape[2]] += temp_img
			weight_img[point[0]:point[0] + img_shape[1], point[1]:point[1] + img_shape[2]] += block_weight
		return basic_img, weight_img

	def __BM3D_step_2(self, basic_img, img):
		width, height = img.shape
		block_size = self.params["Step2_Blk_Size"]
		blk_step = self.params["Step2_Blk_Size"]
		width_num = int((width - block_size) / blk_step)
		height_num = int((height - block_size) / blk_step)
		filtered_img = numpy.zeros(img.shape, dtype=float)
		filter_weight = numpy.zeros(img.shape, dtype=float)

		for i in range(width_num + 2):
			for j in range(height_num + 2):
				BlockPoint = self.__Locate_blk(i, j, blk_step, block_size, width, height)
				basic_similar_blocks_3d, similar_blocks_3d, blk_positions, count = self.__step2_fast_match(basic_img, img,
																									BlockPoint)
				similar_basic_blocks, Wiener_weight = self.__step2_3DFiltering(basic_similar_blocks_3d, similar_blocks_3d)
				filtered_img, filter_weight = self.__integ_Wiener(similar_basic_blocks, Wiener_weight, blk_positions,
														   filtered_img,
														   filter_weight, count)
		filtered_img /= filter_weight
		filtered_img.astype(numpy.uint8)

		return filtered_img

	def denoise(self, dataImage):

		denoised_img = numpy.zeros_like(dataImage[:,:,0])
		final_denoised_img = numpy.zeros_like(dataImage[:,:,0])
		final_denoised_img = bm3dDenoising(dataImage[:,:,0], final_denoised_img)
		#for ch in range(3):
			#denoised_img[:,:,ch] = self.__BM3D_step_1(dataImage[:,:,ch])
			#final_denoised_img[:,:,ch] = self.__BM3D_step_2(denoised_img[:,:,ch], dataImage[:,:,ch])

		return final_denoised_img


MAL_USER_LIST = {
    "data": [
        {
            "node": {
                "id": 30,
                "title": "Neon Genesis Evangelion",
                "main_picture": {
                    "medium": "https://api-cdn.myanimelist.net/images/anime/1314/108941.jpg",
                    "large": "https://api-cdn.myanimelist.net/images/anime/1314/108941l.jpg",
                },
                "nsfw": "white",
                "genres": [
                    {"id": 1, "name": "Action"},
                    {"id": 5, "name": "Avant Garde"},
                    {"id": 46, "name": "Award Winning"},
                    {"id": 8, "name": "Drama"},
                    {"id": 18, "name": "Mecha"},
                    {"id": 40, "name": "Psychological"},
                    {"id": 24, "name": "Sci-Fi"},
                    {"id": 41, "name": "Suspense"},
                ],
                "studios": [
                    {"id": 1, "name": "Test Studio 1"},
                    {"id": 5, "name": "Test Studio 2"},
                ],
                "media_type": "tv",
                "start_season": {"year": 2020, "season": "winter"},
                "rating": "r",
            },
            "list_status": {
                "status": "completed",
                "score": 10,
                "num_episodes_watched": 26,
                "is_rewatching": False,
                "updated_at": "2013-08-09T06:11:09+00:00",
                "tags": [],
            },
        },
        {
            "node": {
                "id": 270,
                "title": "Hellsingfårs",
                "main_picture": {
                    "medium": "https://api-cdn.myanimelist.net/images/anime/10/19956.jpg",
                    "large": "https://api-cdn.myanimelist.net/images/anime/10/19956l.jpg",
                },
                "nsfw": "white",
                "genres": [
                    {"id": 1, "name": "Action"},
                    {"id": 50, "name": "Adult Cast"},
                    {"id": 58, "name": "Gore"},
                    {"id": 14, "name": "Horror"},
                    {"id": 42, "name": "Seinen"},
                    {"id": 37, "name": "Supernatural"},
                    {"id": 32, "name": "Vampire"},
                ],
                "studios": [
                    {"id": 1, "name": "Test Studio 1"},
                    {"id": 5, "name": "Test Studio 2"},
                ],
                "media_type": "tv",
                "start_season": {"year": 2023, "season": "spring"},
                "rating": "r+",
            },
            "list_status": {
                "status": "completed",
                "score": 8,
                "num_episodes_watched": 13,
                "is_rewatching": False,
                "updated_at": "2017-05-26T18:32:10+00:00",
                "tags": [],
            },
        },
    ]
}

ANI_USER_LIST = {
    "data": {
        "MediaListCollection": {
            "lists": [
                {
                    "name": "Watching",
                    "isCustomList": False,
                    "isSplitCompletedList": False,
                    "status": "CURRENT",
                    "entries": [
                        {
                            "status": "CURRENT",
                            "score": 0,
                            "dateStarted": {"year": 2023, "month": 2, "day": 23},
                            "completedAt": {"year": None, "month": None, "day": None},
                            "media": {
                                "id": 131518,
                                "title": {"romaji": "Dr. STRONK: OLD WORLD"},
                                "genres": ["Action", "Adventure", "Comedy", "Sci-Fi"],
                                "tags": [
                                    {"name": "Post-Apocalyptic", "rank": 95},
                                    {"name": "Survival", "rank": 89},
                                    {"name": "Educational", "rank": 88},
                                    {"name": "Male Protagonist", "rank": 85},
                                    {"name": "Ships", "rank": 84},
                                    {"name": "Shounen", "rank": 81},
                                    {"name": "Conspiracy", "rank": 80},
                                    {"name": "Ensemble Cast", "rank": 71},
                                    {"name": "Amnesia", "rank": 60},
                                    {"name": "Espionage", "rank": 60},
                                    {"name": "Found Family", "rank": 60},
                                    {"name": "Crossdressing", "rank": 50},
                                    {"name": "Agriculture", "rank": 40},
                                    {"name": "Butler", "rank": 33},
                                    {"name": "Aliens", "rank": 33},
                                    {"name": "War", "rank": 30},
                                    {"name": "Female Harem", "rank": 10},
                                ],
                                "meanScore": 82,
                                "source": "MANGA",
                                "studios": {"edges": [{"id": 29467}, {"id": 29998}, {"id": 32538}]},
                                "seasonYear": 2023,
                                "season": "SPRING",
                            },
                        },
                        {
                            "status": "COMPLETED",
                            "score": 7,
                            "dateStarted": {"year": 2022, "month": 2, "day": 22},
                            "completedAt": {"year": 2023, "month": 3, "day": 23},
                            "media": {
                                "id": 790,
                                "title": {"romaji": "Argo Roxy"},
                                "genres": ["Adventure", "Mystery", "Psychological", "Sci-Fi"],
                                "tags": [
                                    {"name": "Post-Apocalyptic", "rank": 94},
                                    {"name": "Philosophy", "rank": 93},
                                    {"name": "Dissociative Identities", "rank": 90},
                                    {"name": "Dystopian", "rank": 89},
                                    {"name": "Cyberpunk", "rank": 85},
                                    {"name": "Primarily Adult Cast", "rank": 85},
                                    {"name": "Amnesia", "rank": 85},
                                    {"name": "Robots", "rank": 85},
                                    {"name": "Conspiracy", "rank": 84},
                                    {"name": "Artificial Intelligence", "rank": 80},
                                    {"name": "Anti-Hero", "rank": 79},
                                    {"name": "Noir", "rank": 78},
                                    {"name": "Fugitive", "rank": 74},
                                    {"name": "Memory Manipulation", "rank": 73},
                                    {"name": "Angels", "rank": 73},
                                    {"name": "Female Protagonist", "rank": 72},
                                    {"name": "Denpa", "rank": 70},
                                    {"name": "Male Protagonist", "rank": 68},
                                    {"name": "Tragedy", "rank": 64},
                                    {"name": "Gods", "rank": 60},
                                    {"name": "Travel", "rank": 60},
                                    {"name": "Kuudere", "rank": 52},
                                    {"name": "Police", "rank": 48},
                                    {"name": "Meta", "rank": 40},
                                    {"name": "Coming of Age", "rank": 38},
                                    {"name": "Terrorism", "rank": 35},
                                    {"name": "Guns", "rank": 30},
                                    {"name": "Heterosexual", "rank": 30},
                                    {"name": "Satire", "rank": 12},
                                ],
                            },
                        },
                    ],
                }
            ]
        }
    }
}

MAL_SEASONAL_LIST = {
    "data": [
        {
            "node": {
                "id": 50528,
                "title": "Golden Kamuy 4th Season",
                "main_picture": {
                    "medium": "https://api-cdn.myanimelist.net/images/anime/1855/128059.jpg",
                    "large": "https://api-cdn.myanimelist.net/images/anime/1855/128059l.jpg",
                },
                "genres": [
                    {"id": 1, "name": "Action"},
                    {"id": 50, "name": "Adult Cast"},
                    {"id": 2, "name": "Adventure"},
                    {"id": 13, "name": "Historical"},
                    {"id": 38, "name": "Military"},
                    {"id": 42, "name": "Seinen"},
                ],
                "studios": [
                    {"id": 1, "name": "Test Studio 1"},
                    {"id": 5, "name": "Test Studio 2"},
                ],
                "media_type": "tv",
                "start_season": {"year": 2023, "season": "winter"},
                "rating": "r+",
                "num_list_users": 5,
            }
        },
        {
            "node": {
                "id": 51535,
                "title": "Shingeki no Kyojin: The Fake Season",
                "main_picture": {
                    "medium": "https://api-cdn.myanimelist.net/images/anime/1279/131078.jpg",
                    "large": "https://api-cdn.myanimelist.net/images/anime/1279/131078l.jpg",
                },
                "genres": [
                    {"id": 1, "name": "Action"},
                    {"id": 8, "name": "Drama"},
                    {"id": 58, "name": "Gore"},
                    {"id": 38, "name": "Military"},
                    {"id": 27, "name": "Shounen"},
                    {"id": 76, "name": "Survival"},
                    {"id": 41, "name": "Suspense"},
                ],
                "studios": [
                    {"id": 1, "name": "Test Studio 1"},
                    {"id": 5, "name": "Test Studio 2"},
                ],
                "media_type": "tv",
                "start_season": {"year": 2023, "season": "winter"},
                "rating": "r",
                "num_list_users": 6,
            }
        },
    ]
}

ANI_SEASONAL_LIST = {
    "data": {
        "Page": {
            "pageInfo": {
                "hasNextPage": True,
                "total": 5000,
                "currentPage": 1,
                "lastPage": 100,
                "perPage": 50,
            },
            "media": [
                {
                    "id": 144932,
                    "title": {"romaji": "EDENS KNOCK-OFF 2nd Season"},
                    "season": "SPRING",
                    "seasonYear": 2023,
                    "relations": {
                        "edges": [
                            {"relationType": "PREQUEL", "node": {"id": 119683}},
                            {"relationType": "ADAPTATION", "node": {"id": 101860}},
                        ]
                    },
                    "genres": ["Action", "Adventure", "Drama", "Fantasy", "Supernatural"],
                    "coverImage": {"medium": "https://localhost/test.png"},
                    "popularity": 14090,
                },
                {
                    "id": 145139,
                    "title": {"romaji": "Kimetsu no Yaiba: Katanakaji no Sato-hen"},
                    "season": "SPRING",
                    "seasonYear": 2023,
                    "relations": {
                        "edges": [
                            {"relationType": "ADAPTATION", "node": {"id": 87216}},
                            {"relationType": "PREQUEL", "node": {"id": 142329}},
                        ]
                    },
                    "genres": ["Action", "Adventure", "Comedy", "Fantasy", "Sci-Fi"],
                    "coverImage": {"medium": "https://localhost/test.png"},
                    "popularity": 131620,
                },
            ],
        }
    }
}

FORMATTED_MAL_USER_LIST = [
    {
        "id": 30,
        "title": "Pastel Exodus Evangelion",
        "nsfw": "white",
        "genres": [
            "Action",
            "Avant Garde",
            "Award Winning",
            "Drama",
            "Mecha",
            "Psychological",
            "Sci-Fi",
            "Suspense",
        ],
        "features": [
            "Action",
            "Avant Garde",
            "Award Winning",
            "Drama",
            "Mecha",
            "Psychological",
            "Sci-Fi",
            "Suspense",
            "r",
        ],
        "rating": "r",
        "studios": [
            "Test Studio 1",
            "Test Studio 2",
        ],
        "media_type": "tv",
        "score": 10,
        "user_status": "completed",
        "start_season": "2020/winter",
        "coverImage": "https://localhost/test.png",
        "source": "Original",
        "cluster": 1,
    },
    {
        "id": 270,
        "title": "Hellsingfårs",
        "nsfw": "white",
        "genres": [
            "Action",
            "Adult Cast",
            "Gore",
            "Horror",
            "Seinen",
            "Supernatural",
            "Vampire",
        ],
        "features": [
            "Action",
            "Adult Cast",
            "Gore",
            "Horror",
            "Seinen",
            "Supernatural",
            "Vampire",
            "r+",
        ],
        "rating": "r+",
        "studios": [
            "Test Studio 1",
            "Test Studio 2",
        ],
        "media_type": "tv",
        "score": 8,
        "user_status": "watching",
        "start_season": "2023/spring",
        "coverImage": "https://localhost/test.png",
        "source": "Manga",
        "cluster": 2,
    },
]

FORMATTED_MAL_SEASONAL_LIST = [
    {
        "id": 50528,
        "title": "Copper Kamuy 4th Season",
        "genres": [
            "Action",
            "Adult Cast",
            "Adventure",
            "Historical",
            "Military",
            "Seinen",
        ],
        "features": [
            "Action",
            "Adult Cast",
            "Adventure",
            "Historical",
            "Military",
            "Seinen",
            "r+",
        ],
        "studios": [
            "Test Studio 1",
            "Test Studio 2",
        ],
        "rating": "r+",
        "media_type": "tv",
        "status": None,
        "start_season": "2023/winter",
        "popularity": 1,
        "coverImage": "https://localhost/test.png",
        "relations": [],
        "cluster": 1,
        "source": "Original",
    },
    {
        "id": 51535,
        "title": "Shingeki no Kyojin: The Fake Season",
        "genres": [
            "Action",
            "Drama",
            "Gore",
            "Military",
            "Shounen",
            "Survival",
            "Suspense",
        ],
        "features": [
            "Action",
            "Drama",
            "Gore",
            "Military",
            "Shounen",
            "Survival",
            "Suspense",
            "r",
        ],
        "studios": [
            "Test Studio 1",
            "Test Studio 2",
        ],
        "rating": "r",
        "media_type": "tv",
        "status": None,
        "start_season": "2023/winter",
        "popularity": 2,
        "coverImage": "https://localhost/test.png",
        "relations": [1],
        "cluster": 0,
        "source": "Manga",
    },
]

FORMATTED_ANI_SEASONAL_LIST = [
    {
        "id": 144932,
        "title": "EDENS KNOCK-OFF 2nd Season",
        "start_season": "2023/spring",
        "relations": [],
        "coverImage": "https://localhost/test.png",
        "popularity": 14090,
        "genres": ["Action", "Adventure", "Drama", "Fantasy", "Supernatural"],
        "status": "releasing",
        "features": [
            "Action",
            "Adventure",
            "Drama",
            "Fantasy",
            "Supernatural",
            "Shounen",
            "Super Power",
        ],
    },
    {
        "id": 145139,
        "title": "Usotsu no Yaiba: Katanakaji no Sato-hen",
        "start_season": "2023/spring",
        "relations": [],
        "coverImage": "https://localhost/test.png",
        "popularity": 131620,
        "genres": ["Action", "Adventure", "Comedy", "Fantasy", "Sci-Fi"],
        "status": "not_yet_released",
        "features": ["Action", "Adventure", "Comedy", "Fantasy", "Sci-Fi", "Mythology", "Gore"],
    },
]

MAL_RELATED_ANIME = {
    "id": 30,
    "title": "Neon Genesis Evangelion",
    "main_picture": {
        "medium": "https://api-cdn.myanimelist.net/images/anime/1314/108941.jpg",
        "large": "https://api-cdn.myanimelist.net/images/anime/1314/108941l.jpg",
    },
    "related_anime": [
        {
            "node": {
                "id": 31,
                "title": "Neon Genesis Evangelion Season 0",
            },
            "relation_type": "prequel",
            "relation_type_formatted": "prequel",
        }
    ],
}


from collections import defaultdict
import collections
from typing import DefaultDict
import plotly.graph_objects as go
import numpy as np
import random

def text_wierzcholkow(tabela):
    ostateczna_tabela = []
    for i in tabela:
        if len(i[0]) > 1:
            if i[0] == 'SPACE':
                ostateczna_tabela.append(i)
            else:
                ostateczna_tabela.append(i[1])
        else:
            ostateczna_tabela.append(i)

    return ostateczna_tabela

class Drzewo:
    def __init__(self,dane):
        self.drzewo = defaultdict(list)
        self.drzewo[dane]
        self.drzewo[dane].append(None) #adres ojca
        self.drzewo[dane].append(None) #adres lewego syna
        self.drzewo[dane].append(None) # adres prawego syna
    iterator = 0
    def DodawanieDrzew(self,drugie_drzewo):

        dane1 = [*self.drzewo][0]
        dane2 = [*drugie_drzewo.drzewo][0]

        nowe_dane = dane1[1] + dane2[1]
        nowe_drzewo = Drzewo((dane1[0]+dane2[0],nowe_dane))
        if dane1[1] >= dane2[1]:
            nowe_drzewo.DodajDrzewozPrawej(self)
            nowe_drzewo.DodajDrzewozLewej(drugie_drzewo)
            return nowe_drzewo
        else:
            #print(isinstance(drugie_drzewo,Drzewo))
            nowe_drzewo.DodajDrzewozLewej(self)
            nowe_drzewo.DodajDrzewozPrawej(drugie_drzewo)
            return nowe_drzewo

    def DodajDrzewozLewej(self,drzewo_z_lewej):
        #print(dict(drzewo_z_lewej.drzewo))
        for i in drzewo_z_lewej.drzewo.keys():
            if drzewo_z_lewej.drzewo[i][0] is None:
                self.drzewo[self.ZwrocKorzen()][1] = i
                self.drzewo[i].append(self.ZwrocKorzen())
                self.drzewo[i].append(None)
                self.drzewo[i].append(None)
            else:
                tmp_ojciec = drzewo_z_lewej.drzewo[i][0]
                if i in [*self.drzewo]:
                    #print(i,tmp_ojciec,"dodaj z lewej")
                    tmp_i = (i[0],i[1]+0.1)
                    if drzewo_z_lewej.drzewo[tmp_ojciec][1] == i:
                        self.drzewo[tmp_ojciec][1] = tmp_i
                        self.drzewo[tmp_i].append(tmp_ojciec)
                        self.drzewo[tmp_i].append(None)
                        self.drzewo[tmp_i].append(None)
                    if drzewo_z_lewej.drzewo[tmp_ojciec][2] == i:
                        self.drzewo[tmp_ojciec][2] = tmp_i
                        self.drzewo[tmp_i].append(tmp_ojciec)
                        self.drzewo[tmp_i].append(None)
                        self.drzewo[tmp_i].append(None)
                else:
                    if drzewo_z_lewej.drzewo[tmp_ojciec][1] == i:
                        self.drzewo[tmp_ojciec][1] = i
                        self.drzewo[i].append(tmp_ojciec)
                        self.drzewo[i].append(None)
                        self.drzewo[i].append(None)
                    if drzewo_z_lewej.drzewo[tmp_ojciec][2] == i:
                        #print(i,self.drzewo[tmp_ojciec])
                        self.drzewo[tmp_ojciec][2] = i
                        self.drzewo[i].append(tmp_ojciec)
                        self.drzewo[i].append(None)
                        self.drzewo[i].append(None)

    def DodajDrzewozPrawej(self,drzewo_z_prawej):
        #print(dict(drzewo_z_prawej.drzewo))
        #print(drzewo_z_prawej.drzewo.keys())
        for i in drzewo_z_prawej.drzewo.keys():

            if drzewo_z_prawej.drzewo[i][0] is None:
                self.drzewo[self.ZwrocKorzen()][2] = i
                self.drzewo[i].append(self.ZwrocKorzen())
                self.drzewo[i].append(None)
                self.drzewo[i].append(None)
            else:
                tmp_ojciec = drzewo_z_prawej.drzewo[i][0]
                if i in [*self.drzewo]:
                    #print(i,tmp_ojciec,'z prawej')
                    tmp_i = (i[0],i[1]+0.1)
                   # print(drzewo_z_prawej.ZwrocDzieci(tmp_ojciec))
                    if drzewo_z_prawej.drzewo[tmp_ojciec][1] == i:
                       # print('lewy syn prawego')
                        self.drzewo[tmp_ojciec][1] = tmp_i
                        self.drzewo[tmp_i].append(tmp_ojciec)
                        self.drzewo[tmp_i].append(None)
                        self.drzewo[tmp_i].append(None)
                    if drzewo_z_prawej.drzewo[tmp_ojciec][2] == i:
                        #print('prawy syn prawego')
                        self.drzewo[tmp_ojciec][2] = tmp_i
                        self.drzewo[tmp_i].append(tmp_ojciec)
                        self.drzewo[tmp_i].append(None)
                        self.drzewo[tmp_i].append(None)
                else:
                    if drzewo_z_prawej.drzewo[tmp_ojciec][1] == i:
                        self.drzewo[tmp_ojciec][1] = i
                        self.drzewo[i].append(tmp_ojciec)
                        self.drzewo[i].append(None)
                        self.drzewo[i].append(None)
                    if drzewo_z_prawej.drzewo[tmp_ojciec][2] == i:
                        self.drzewo[tmp_ojciec][2] = i
                        self.drzewo[i].append(tmp_ojciec)
                        self.drzewo[i].append(None)
                        self.drzewo[i].append(None)

    def DodajzLewej(self,ojciec,dane):

        self.drzewo[dane]
        self.drzewo[dane].append(ojciec)
        self.drzewo[dane].append(None)
        self.drzewo[dane].append(None)
        self.drzewo[ojciec][1] = dane
    def DodajzPrawej(self,ojciec,dane):

        self.drzewo[dane]
        self.drzewo[dane].append(ojciec)
        self.drzewo[dane].append(None)
        self.drzewo[dane].append(None)
        self.drzewo[ojciec][2] = dane

    def DodajKolejny(self,dane):
        if dane in [*self.drzewo]:
            print("Błąd! istnieje już taki węzeł!")
        else:
            self.Wszystkie_Glebokosci(0)
            for i in range(max(self.glebokosci.values()) + 1):
                for k in [*self.glebokosci]:
                    if self.glebokosci[k] == i:

                        if self.drzewo[k][1] is None:
                            self.drzewo[k][1] = dane
                            self.drzewo[dane].append(k)
                            self.drzewo[dane].append(None)
                            self.drzewo[dane].append(None)
                            return "done"

                        elif self.drzewo[k][2] is None:
                            self.drzewo[k][2] = dane
                            self.drzewo[dane].append(k)
                            self.drzewo[dane].append(None)
                            self.drzewo[dane].append(None)

                            return "done"
                    else:
                        continue

    def Generator_wykresu(self):
        węzły  = [*self.drzewo]

         #współrzędne x kulek
        Y_wierzcholki = [] #współrzędne y kulek
        X_krawedzie = [] #współrzędne x linii
        Y_krawedzie = [] #współrzędne y linii
        self.Wszystkie_Glebokosci(węzły[0])
        wysokosc = (max(self.glebokosci.values())) + 2
        szerokosc = wysokosc + 10
        X_wierzcholki = {}

        def wspolrzedne_x(wezel,X_w):

                    ojciec = self.drzewo[wezel][0]
                    if ojciec is None:
                        tmp = szerokosc / 2
                        X_w.update({wezel:tmp})
                        return tmp

                    x_ojca = X_w[ojciec]
                    if wezel == self.drzewo[ojciec][1]:
                        tmp = x_ojca - 1
                        poprzednik = [*X_w][-1]
                        #print(poprzednik)
                        if self.glebokosci[poprzednik] > 2 and self.glebokosci[poprzednik] == self.glebokosci[wezel]:
                            #print(wezel,poprzednik,self.glebokosci[poprzednik],ojciec)
                            if poprzednik == self.drzewo[ojciec][1]:
                                if tmp < X_w[poprzednik] + 0.1:
                                    print(X_w[poprzednik])
                                    tmp = random.uniform(X_w[poprzednik] + 0.3, X_w[poprzednik] + 0.5)
                                    X_w.update({wezel: tmp})
                                    return tmp  # Dokończyć błąd z przeskakiwaniem
                                else:
                                    if tmp < X_w[poprzednik] + 0.1:
                                        print(X_w[poprzednik])
                                        tmp = random.uniform(X_w[poprzednik] + 0.3, X_w[poprzednik] + 0.5)
                                        X_w.update({wezel: tmp})
                                        return tmp
                                    else:
                                        X_w.update({wezel: tmp})
                                        return tmp
                            else:
                                if tmp < X_w[poprzednik] - 0.03:
                                    # print(X_w[poprzednik])
                                    tmp = random.uniform(X_w[poprzednik] - 0.3, X_w[poprzednik] - 0.5)
                                    X_w.update({wezel: tmp})
                                    return tmp  # Dokończyć błąd z przeskakiwaniem
                                else:

                                    X_w.update({wezel: tmp})
                                    return tmp
                        else:
                            if tmp in X_w.values():
                                tmp = random.uniform(tmp,x_ojca)
                                X_w.update({wezel:tmp})
                                return tmp
                            else:

                                X_w.update({wezel:tmp})
                                return tmp
                    elif wezel == self.drzewo[ojciec][2]:
                        tmp = x_ojca + 0.6
                        poprzednik = [*X_w][-1]
                        if self.glebokosci[poprzednik] > 2 and self.glebokosci[poprzednik] == self.glebokosci[wezel]:
                            if tmp < X_w[poprzednik]:
                                if poprzednik == self.drzewo[ojciec][1]:
                                    tmp = random.uniform(X_w[poprzednik] + 0.3, X_w[poprzednik] + 0.5)
                                    if tmp in X_w.values():
                                        tmp = random.uniform(tmp, x_ojca)
                                        X_w.update({wezel: tmp})
                                        return tmp
                                    else:
                                        X_w.update({wezel: tmp})
                                        return tmp  # Dokończyć błąd z przeskakiwaniem
                                else:
                                    tmp = random.uniform(X_w[poprzednik] + 0.3, X_w[poprzednik] + 0.5)
                                    if tmp in X_w.values():
                                        tmp = random.uniform(tmp, x_ojca)
                                        X_w.update({wezel: tmp})
                                        return tmp
                                    else:
                                        X_w.update({wezel: tmp})
                                        return tmp  # Dokończyć błąd z przeskakiwaniem
                            else:
                                X_w.update({wezel:tmp})
                                return tmp
                        else:
                            if tmp in X_w.values():
                                    tmp = random.uniform(tmp,x_ojca)
                                    X_w.update({wezel:tmp})
                                    return tmp
                            else:
                                X_w.update({wezel:tmp})
                                return tmp

        Y_w = {}
        X_data = []
        # for i in reversed(self.glebokosci):
        #     if i is None:
        #         continue
        #     else:
        #         print(i,self.glebokosci[i])
        #         X_data.append(wspolrzedne_x(i,X_wierzcholki))
        #         Y_w.update({i:wysokosc - self.glebokosci[i]})
        #         Y_wierzcholki +=[wysokosc - self.glebokosci[i]]
        for i in self.drzewo.keys():
            #print(i)
            if i is None:
                continue
            else:
                #print(i,self.drzewo[i])
                #X_data += [X_wierzcholki[i]]

                X_data.append(wspolrzedne_x(i,X_wierzcholki))
                Y_w.update({i:wysokosc - self.glebokosci[i]})
                Y_wierzcholki += [wysokosc - self.glebokosci[i]]

        self.Krawedzie(węzły[0])

        for k in self.krawedzie.items():
            for j in k[1]:
                X_krawedzie.append([X_wierzcholki[k[0]],X_wierzcholki[j]])
                Y_krawedzie.append([Y_w[k[0]],Y_w[j]])

        #print(Y_wierzcholki)
        # ustalic wysokosc dla kazdego wierzcholka dzieki temu okresli sie wysokosc kolejnego

        linie = go.Scatter(x = X_krawedzie,y = [4,3,4,3,3,2,3,2,3,2,3,2],mode = 'lines',connectgaps = True,
        line = dict(color='rgb(10,50,150)', width=2))
        kulki = go.Scatter(x = X_data,y = Y_wierzcholki,
        mode = 'markers+text',
        name = 'kulki',
        text = text_wierzcholkow([*X_wierzcholki]),
        marker=dict(symbol='circle-dot',
                                size=45,
                                color='#6175c1',    #'#DB4551',
                                line=dict(color='rgb(50,50,50)', width=1)
                                ))
        fig = go.Figure(data=[kulki])
        for i in range(len(X_krawedzie)):
            tmp = go.Scatter(x = X_krawedzie[i],y = Y_krawedzie[i],
            mode = 'lines',
            line = dict(color = 'rgb(10,50,150)',width = 1))
            fig.add_trace(tmp)
        fig.show()
        #fig.write_html('tmp2.html',auto_open = True)

    glebokosci = {}
    wezly = []

    def DFS(self,wezel):
        if self.drzewo[wezel]:
            print (wezel,self.kody_huffmana[wezel])

            self.DFS(self.drzewo[wezel][1])
            self.DFS(self.drzewo[wezel][2])
    dfs_wezly = []

    def TablicaWezlow(self,wezel): # Naprawić dziwne tworzenie węzłów
        if self.drzewo[wezel]:
            self.wezly.append(wezel)
            self.TablicaWezlow(self.drzewo[wezel][1])
            self.TablicaWezlow(self.drzewo[wezel][2])
    krawedzie = defaultdict(list)

    def Krawedzie(self,wezel): # powinno wywolac je sie dla korzenia
        if self.drzewo[wezel]:
            if self.drzewo[wezel][1] is not None:
                self.krawedzie[wezel].append(self.drzewo[wezel][1])
                self.Krawedzie(self.drzewo[wezel][1])
            if self.drzewo[wezel][2] is not None:
                self.krawedzie[wezel].append(self.drzewo[wezel][2])
                self.Krawedzie(self.drzewo[wezel][2])

    def Krawedzie_test(self):
        return dict(self.krawedzie)

    glebokosc = 0

    def Glebokosc_Wezla(self,wezel):
        if self.drzewo[wezel][0] is not None:
            self.glebokosc += 1
            self.Glebokosc_Wezla(self.drzewo[wezel][0])
        else:
            #self.glebokosc = self.glebokosc
            return self.glebokosc

            #print(self.glebokosc)
    def Wszystkie_Glebokosci(self,wezel):
        if self.drzewo[wezel]:
            self.Glebokosc_Wezla(wezel)
            tmp = self.ZwrocGlebokosc()
            self.glebokosci.update({wezel:tmp})
            self.Wszystkie_Glebokosci(self.drzewo[wezel][1])
            self.Wszystkie_Glebokosci(self.drzewo[wezel][2])
    def ZwrocOjca(self,wezel):
        return self.drzewo[wezel][0]

    def ZwrocDzieci(self,wezel):
        return {"lewy syn":self.drzewo[wezel][1],"prawy syn":self.drzewo[wezel][2]}
    def ZwrocGlebokosc(self):
        tmp = self.glebokosc
        self.glebokosc = 0
        return tmp
    def ZwrocGlebokosci(self):
        return self.glebokosci
    def ZwrocKorzen(self):
        return [*self.drzewo][0]
    def PrintDrzewo(self):
        self.DFS(self.ZwrocKorzen())
        print('-----')
        return 0
    def ZwrocKorzen(self):
        return [*self.drzewo][0]
    kody_huffmana = {}
    def OznaczanieWezla(self,wezel,tmp):
        if self.drzewo[wezel]:
            ojciec = self.drzewo[wezel][0]
            if ojciec is None:
                self.OznaczanieWezla(self.drzewo[wezel][1], tmp)
                self.OznaczanieWezla(self.drzewo[wezel][2], tmp)
            else:
                #print(wezel)
                if wezel == self.drzewo[ojciec][1]:
                    tmp += '0'
                    if wezel in self.kody_huffmana:
                        return None
                    else:
                        self.kody_huffmana.update({wezel:tmp})

                else:
                    tmp += '1'
                    if wezel in self.kody_huffmana:
                        return None
                    else:
                        self.kody_huffmana.update({wezel:tmp})
                self.OznaczanieWezla(self.drzewo[wezel][1], tmp)
                self.OznaczanieWezla(self.drzewo[wezel][2], tmp)
    def ZwrocKody(self):
        klucze_do_usuniecia = []
        for i in self.kody_huffmana.keys():
            if len(i[0]) > 1 and i[0] != 'SPACE' and i[0] != '\n':
                klucze_do_usuniecia.append(i)
        for i in klucze_do_usuniecia:
            self.kody_huffmana.pop(i)
        nowe_kody = dict()
        tmp = None
        for i in self.kody_huffmana.keys():
            tmp = i[0]
            nowe_kody.update({tmp:self.kody_huffmana[i]})
        nowe_kody.update({' ':nowe_kody['SPACE']})
        nowe_kody.pop('SPACE')
        return nowe_kody
        # elif wezel == self.drzewo[ojciec][1]:
        #     if self.kody_huffmana[wezel]:
        #         tmp = self.kody_huffmana[wezel]
        #         self.kody_huffmana.update({wezel:tmp+'0'})
        #     else:
        #         self.kody_huffmana.update({wezel:'0'})
        # elif wezel == self.drzewo[ojciec][2]:
        #     if self.kody_huffmana[wezel]:
        #         tmp = self.kody_huffmana[wezel]
        #         self.kody_huffmana.update({wezel:tmp+'1'})
        #     else:
        #         self.kody_huffmana.update({wezel:'1'})


# coding: utf-8
import os
import pandas as pd
import re

from stats_per_folder import compute_by_folder

RE_D = re.compile('\d')

extensions = ["-fair_levenshtein_0.2/", "-fair_exact/", "-fair_exact_vocab/", "-fair_levenshtein_train_0.2/"]

paths_of_interest = [

    {"name": "MANTRA-de",
     "test": "data/datasets/mantra/de/DISO",
     },
    {"name": "MANTRA-en",
     "test": "data/datasets/mantra/en/DISO",
     },
    {"name": "MANTRA-es",
     "test": "data/datasets/mantra/es/DISO",
     },
    {"name": "MANTRA-fr",
     "test": "data/datasets/mantra/fr/DISO",
     },
    {"name": "MANTRA-nl",
     "test": "data/datasets/mantra/nl/DISO",
     },

    {"name": "CANTEMIST",
     "train": "data/datasets/cantemist/train-set/cantemist-norm-concepts",
     "test": "data/datasets/cantemist/test-set/cantemist-norm-concepts",
     },

    {"name": "codiesp-d",
     "train": "data/datasets/codiesp/DIAGNOSTICO/train",
     "test": "data/datasets/codiesp/DIAGNOSTICO/test",
     },

    {"name": "codiesp-p",
     "train": "data/datasets/codiesp/PROCEDIMIENTO/train",
     "test": "data/datasets/codiesp/PROCEDIMIENTO/test",
     },

    {"name": "mcn",
     "train": "data/datasets/MCN_n2c2/biosyn_processed_pairs/train",
     "test": "data/datasets/MCN_n2c2/biosyn_processed_pairs/test",
     },
]

if __name__ == "__main__":

    dataframe = []

    for path_bunch in paths_of_interest:

        base_directory_test = path_bunch["test"] + "/"
        print("\n\nBase test directory:", base_directory_test)

        # train
        train_stats = None
        unique_ids_train = None

        try:
            base_train_directory = path_bunch["train"] + "/"

            if not os.path.exists(base_train_directory):
                print(f"Path {base_train_directory} doesn't exist.")
                continue

            train_stats, unique_ids_train = compute_by_folder(base_train_directory)
            train_stats["dir"] = base_train_directory
            dataframe.append(train_stats)
        except:
            print("train set not available")

        # test

        if not os.path.exists(base_directory_test):
            print(f"Path {base_directory_test} doesn't exist.")
            raise Exception()

        test_stats, unique_ids_test = compute_by_folder(base_directory_test)
        test_stats["dir"] = base_directory_test
        dataframe.append(test_stats)

        ## full

        if train_stats is None:
            full_stats = test_stats.copy()
            full_stats["avg_numbers"] = "%.2f" % ((test_stats["sum_chars"]) / full_stats["number_of_mentions"])
            full_stats["have_numbers"] = "%2.2f\\%%" % (test_stats["have_numbers"] / full_stats["number_of_mentions"] * 100)
        else:
            full_stats = {}
            full_stats["number_of_mentions"] = train_stats["number_of_mentions"] + test_stats["number_of_mentions"]
            full_stats["number_of_concepts"] = len(unique_ids_test.union(unique_ids_train))
            have_numbers = train_stats["have_numbers"] + test_stats["have_numbers"]
            full_stats["have_numbers"] = "%2.2f\\%%" % (have_numbers / full_stats["number_of_mentions"] * 100)
            full_stats["avg_numbers"] = "%.2f" % (
                        (train_stats["sum_chars"] + test_stats["sum_chars"]) / full_stats["number_of_mentions"])
            full_stats["intersect_train"] = len(unique_ids_train.intersection(unique_ids_test))

        full_stats["dir"] = "FULL"
        dataframe.append(full_stats)
        current_stats = {}

        for extension in extensions:
            directory = path_bunch["test"] + extension

            if not os.path.exists(directory):
                print(f"Path {directory} doesn't exist.")
                continue

            stats, unique_ids = compute_by_folder(directory)
            stats["dir"] = directory
            stats["number_of_mentions"] = f"({stats['number_of_mentions']}) %2.1f\\%%" % (100 *
                                                                                stats['number_of_mentions'] /
                                                                                test_stats["number_of_mentions"])
            if unique_ids_train is not None:
                stats["intersect_train"] = len(unique_ids_train.intersection(unique_ids))

            dataframe.append(stats)

    df = pd.DataFrame(dataframe)
    df.to_csv("datasets_stats.csv", index=None)


# Problem Link: https://leetcode.com/problems/add-two-numbers/

class Solution:
	def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
		suml = self.reverse(l1) + self.reverse(l2)
		head = prev = None
		for x in str(suml)[::-1]:
			node = ListNode(x)
			if prev is not None:
				prev.next = node
			prev = node
			if head is None:
				head = prev
		return head

	def reverse(self, l: ListNode):
		n = ''
		while l is not None:
			n = n + str(l.val)
			l = l.next
		return(int(n[::-1]))


import pygame
from OpenGL.GLU import *
from math import *

class Camera:
    def __init__(self, screen_width, screen_height):
        self.eye = pygame.math.Vector3(0, 0, 0)
        self.up = pygame.math.Vector3(0, 1, 0)
        self.right = pygame.math.Vector3(1, 0, 0)
        self.forward = pygame.math.Vector3(0, 0, 1)
        self.look = self.eye + self.forward
        self.yaw = -90
        self.pitch = 0
        self.last_mouse = pygame.math.Vector2(screen_width // 2, screen_height // 2)
        self.mouse_sensitivityX = 0.1
        self.mouse_sensitivityY = 0.1

        pygame.mouse.set_visible(False)
        pygame.mouse.set_pos(screen_width // 2, screen_height // 2)

    def rotate(self, yaw, pitch):
        self.yaw += yaw
        self.pitch += pitch

        if self.pitch > 89.0:
            self.pitch = 89.0
        if self.pitch < -89.0:
            self.pitch = -89.0

        self.forward.x = cos(radians(self.yaw)) * cos(radians(self.pitch))
        self.forward.y = sin(radians(self.pitch))
        self.forward.z = sin(radians(self.yaw)) * cos(radians(self.pitch))
        self.forward = self.forward.normalize()
        self.right = self.forward.cross(pygame.Vector3(0, 1, 0)).normalize()
        self.up = self.right.cross(self.forward).normalize()

    def update(self, screen_width, screen_height):
        # Get the current mouse position
        mouse_pos = pygame.mouse.get_pos()

        # Calculate the change in mouse position from the center
        mouse_change = pygame.math.Vector2(mouse_pos[0] - screen_width // 2, mouse_pos[1] - screen_height // 2)

        # Re-center the mouse pointer
        pygame.mouse.set_pos(screen_width // 2, screen_height // 2)

        # Update the camera rotation based on mouse movement
        self.rotate(mouse_change.x * self.mouse_sensitivityX, mouse_change.y * self.mouse_sensitivityY)

        keys = pygame.key.get_pressed()
        # Camera movement speed
        move_speed = 0.1

        if keys[pygame.K_DOWN]:
            # Move the camera backward (along the negative self.forward direction)
            self.eye -= self.forward * move_speed
        if keys[pygame.K_UP]:
            # Move the camera forward (along the self.forward direction)
            self.eye += self.forward * move_speed
        if keys[pygame.K_LEFT]:
            # Move the camera left (along the self.right direction)
            self.eye -= self.right * move_speed
        if keys[pygame.K_RIGHT]:
            # Move the camera right (along the self.right direction)
            self.eye += self.right * move_speed
        if keys[pygame.K_PAGEUP]:
            # Move the camera up (along the self.up direction)
            self.eye += self.up * move_speed
        if keys[pygame.K_PAGEDOWN]:
            # Move the camera down (along the negative self.up direction)
            self.eye -= self.up * move_speed

        self.look = self.eye + self.forward
        gluLookAt(self.eye.x, self.eye.y, self.eye.z,
                  self.look.x, self.look.y, self.look.z,
                  self.up.x, self.up.y, self.up.z)


from .field import Field

class Geometry(Field):
    _type = 'geometry'

    def __init__(self, string='', srid=4326, dimension=2, required=False,
            readonly=False, domain=None, depends=None, select=False,
            order_field=None, context=None, states=None, on_change=None,
            on_change_with=None, loading='lazy', help=''):
        super(Geometry, self).__init__(string=string, help=help,
            required=required, readonly=readonly, domain=domain, states=states,
            select=select, on_change=on_change, on_change_with=on_change_with,
            depends=depends, order_field=order_field, context=context,
            loading=loading)
        self.dimension = dimension
        self.srid = srid

class Point(Geometry):
    _type = 'point'

class LineString(Geometry):
    _type = 'linestring'

class Polygon(Geometry):
    _type = 'polygon'

class MultiPoint(Geometry):
    _type = 'multipoint'

class MultiLineString(Geometry):
    _type = 'multilinestring'

class MultiPolygon(Geometry):
    _type = 'multipolygon'

class GeometryCollection(Geometry):
    _type = 'geometrycollection'


import pytest
from ezread import EzReader

@pytest.mark.parametrize(
    "template, expected_rows",
    [
        ("""["name"]""", [["Tom"], ["Dick"], ["Harry"]]),
        ("""["name", "age"]""", [["Tom", 30], ["Dick", 20], ["Harry", 40]]),
        (
            """["name", "age", ["address", "street", 0]]""",
            [
                ["Tom", 30, "124 Lincoln St"],
                ["Dick", 20, "125 Lincoln St"],
                ["Harry", 40, "50 Vinci Lane"],
            ],
        ),
    ],
)
def test_read(list_of_dicts_json, template, expected_rows):
    er = EzReader(template)
    assert expected_rows == er.read(list_of_dicts_json)

@pytest.mark.parametrize(
    "template",
    [
        """["name", "age", ["address", "zip"]]""",  # zip being the missing key.
        """["name", "profession"]""",  # profession being the missing key.
    ],
)
def test_missingkeys_strict_read(list_of_dicts_json, template):
    er = EzReader(template)
    with pytest.raises(KeyError):
        er.read(list_of_dicts_json)

@pytest.mark.parametrize(
    "template, expected_rows",
    [
        (
            """["name", "age", ["address", "zip"]]""",  # zip being the missing key.
            [["Tom", 30, None], ["Dick", 20, None], ["Harry", 40, None]],
        ),
        (
            """["name", "profession"]""",  # profession being the missing key.
            [["Tom", None], ["Dick", None], ["Harry", None]],
        ),
    ],
)
def test_missingkeys_nonstrict_read(list_of_dicts_json, template, expected_rows):
    er = EzReader(template, strict=False)
    assert expected_rows == er.read(list_of_dicts_json)


import argparse
import csv
from pathlib import Path
import shutil

import pandas as pd
import gin

def metric(seeds_dir, error_name='l1', verbose=False):
    # average of last 10 epochs
    results_path = Path(seeds_dir)

    # if verbose:
        # print(results_path.name)

    run_logs = []
    for path in results_path.glob('*/logs.json'):
        # if verbose:
            # print(path)
        with open(path, 'r') as logfile:
            try:
                run_logs.append(pd.read_json(logfile))
            except ValueError as e:
                raise ValueError(f'cant read json {path}: {e}')

    if not run_logs:
        return None

    gin.parse_config_file(results_path / '0/config.gin', skip_unknown=True)
    # if gin.config.query_parameter('Gaussian.dim') < 32:
        # return None

    logs = pd.concat(run_logs, ignore_index=True)
    epoch = logs['epoch']
    sender = pd.DataFrame(logs['sender'].tolist()).join(logs['epoch'])
    recver = pd.DataFrame(logs['recver'].tolist()).join(logs['epoch'])
    if error_name == 'l1' and 'test_l1_error' in sender:
        error_metric = 'test_l1_error'
    elif error_name == 'l2' and 'test_l2_error' in sender:
        error_metric = 'test_l2_error'
    elif error_name == 'train':
        error_metric = 'test_error'
    else:
        raise Exception(f'error name {error_name} either not found or not valid')

    last_10 = logs['epoch'] >= 20
    if error_name == 'l1' and (sender[last_10][error_metric].mean() > 9 and recver[last_10][error_metric].mean() > 9):
        return None
    # elif error_name == 'l2' and (sender[last_10][error_metric].mean() > 120 and recver[last_10][error_metric].mean() > 120):
        # __import__('pdb').set_trace()
        # return None
    else:
        total_error = sender[error_metric] + recver[error_metric]
        if total_error.isnull().values.any():
            return None
        else:
            score = total_error.to_frame().groupby(epoch).mean()[-10:].mean()[error_metric]
            return score

def metric_over_runs(all_results_dir, error_name, verbose=True):
    all_results_path = Path(all_results_dir)

    empty =  []
    errors = []
    min_score = None
    min_index = None
    min_l1 = None
    num_runs = 0
    for result_dir in all_results_path.iterdir():
        if result_dir.is_dir():
            try:
                score = metric(result_dir, error_name, verbose)
                if error_name != 'l1':
                    l1 = metric(result_dir, 'l1', verbose)
                else:
                    l1 = score
            except ValueError:
                errors.append(result_dir.name)
            else:
                if score is None:
                    empty.append(result_dir.name)
                elif min_score is None or score < min_score:
                    min_score = score
                    min_index = result_dir.name
                    min_l1 = l1
                    num_runs += 1
                else:
                    num_runs += 1

    if verbose:
        print(f'Empty dirs {empty}')
        print(f'Error dirs {errors}')
        print(f'Number of runs {num_runs}')

    return min_score, min_index, min_l1

def generate_results_csv(experiment_name, cluster_dir, output_dir='.', error_name='l1', verbose=False):
    output_path = Path(output_dir)
    cluster_results_path = Path(cluster_dir)
    if not cluster_results_path.exists():
        raise Exception(f'results path {cluster_results_path} does not exist')

    biases = []
    best_errors = []
    best_l1s = []
    ids = []
    run_paths = []

    for exp_results_path in cluster_results_path.glob(f'{experiment_name}-bias*'):
        exp_full_name = exp_results_path.name
        bias_index = exp_full_name.find('bias') + 4
        name_index = len(exp_full_name) + 1
        print(f'running on {exp_full_name}')
        error, run_name, l1 = metric_over_runs(exp_results_path, error_name=error_name, verbose=verbose)
        if error is None:
            print(f'no results in {exp_full_name}')
        else:
            biases.append(int(exp_full_name[bias_index:]))
            best_errors.append(error)
            best_l1s.append(l1)
            ids.append(run_name[name_index:])
            run_paths.append(exp_results_path / run_name)

    if not run_paths:
        raise Exception(f'could not find any experiment {experiment_name} in {cluster_results_path}')

    with open(output_path / 'results.csv', 'w') as f:
        writer = csv.writer(f)
        writer.writerow(['bias', 'error', 'id', 'l1'])
        for bias, error, id_, l1 in sorted(zip(biases, best_errors, ids, best_l1s)):
            writer.writerow([bias, error, id_, l1])

    return run_paths

def generate_results_folder(experiment_name, cluster_dir, output_path, error_name, verbose=False):
    output_path = Path(output_path)
    output_path.mkdir(exist_ok=True)

    print('generating results csv')
    best_run_paths = generate_results_csv(experiment_name, cluster_dir, output_path, error_name, verbose)

    print('copying files')
    for run_path in best_run_paths:
        dest = output_path / run_path.name
        if dest.exists():
            shutil.rmtree(str(dest))
        shutil.copytree(str(run_path), str(dest))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()

    # generate results folder
    gen_parser = subparsers.add_parser('generate')
    gen_parser.set_defaults(command='generate')
    gen_parser.add_argument('--experiment-name', '--exp-name', required=True)
    gen_parser.add_argument('--results-dir', default='/scratch/')
    gen_parser.add_argument('--output-dir', default=None)
    gen_parser.add_argument('--error', default='l1')
    gen_parser.add_argument('--verbose', action='store_true')

    # get error metric over hyperparams
    check_parser = subparsers.add_parser('check')
    check_parser.set_defaults(command='check')
    check_parser.add_argument('dir')
    check_parser.add_argument('--error', default='l1')

    args = parser.parse_args()

    if args.command == 'generate':
        generate_results_folder(args.experiment_name,
                                args.results_dir,
                                args.output_dir,
                                args.error,
                                args.verbose)
    elif args.command == 'check':
        print(metric_over_runs(args.dir, args.error))


import math

def entropy(partition):
    result = 0
    base = sum(partition)
    for i in partition:
        if(i != 0):
            result += -i/base * math.log(i/base, 2)
    return result

def program(count, m = 2, n = 2):

    if(len(count[0]) != m or len(count) != n):
        print('Invalid input data')
        return

    rootPartition = []
    for i in range(0, m):
        temp = 0
        for j in range(0, n):
            temp += count[j][i]
        rootPartition.append(temp)

    print('Root entropy: %f'%entropy(rootPartition))

    for i in range(0, n):
        print('Specific conditional entropy for node %d: %f' % (i, entropy(count[i])))

    avgConditionalEntropy = 0
    for i in range(0, n):
        avgConditionalEntropy += sum(count[i]) / sum(rootPartition) * entropy(count[i])

    print('Average condition entropy: %f' % avgConditionalEntropy)

    print('Information gain: %f' % (entropy(rootPartition) - avgConditionalEntropy))

program([[2, 1, 1], [0, 1, 1]], 3, 2)


from __future__ import print_function

from collections import Counter
import glob
import multiprocessing
import os
import re
import sys
import time

import pandas as pd

print('--- Read training labels')
train_labels = pd.read_csv('data/train_v2.csv')
train_keys = dict([a[1] for a in train_labels.iterrows()])
test_files = set(pd.read_csv('data/sampleSubmission_v2.csv').file.values)

def create_data(filepath):
    values = {}
    filename = os.path.basename(filepath)
    with open(filepath, 'rb') as infile:
        text = infile.read()
    values['file'] = filename
    if filename in train_keys:
        values['sponsored'] = train_keys[filename]
    values['lines'] = text.count('\n')
    values['spaces'] = text.count(' ')
    values['tabs'] = text.count('\t')
    values['braces'] = text.count('{')
    values['brackets'] = text.count('[')
    values['words'] = len(re.split('\s+', text))
    values['length'] = len(text)

    values['http'] = text.count('http')
    values['meta'] = text.count('meta')
    values['link'] = text.count('link')
    values['img'] = text.count('img')
    values['script'] = text.count('script')
    values['href'] = text.count('href')
    values['style'] = text.count('style')
    values['<div'] = text.count('<div')
    values['<a'] = text.count('<a')
    values['<p'] = text.count('<p')
    values['<span'] = text.count('<span')
    values['<ul'] = text.count('<ul')
    values['<li'] = text.count('<li')

    return values

filepaths = glob.glob('data/*/*.txt')

num_tasks = len(filepaths)

print(num_tasks)

print("working...")

results = map(create_data, filepaths)

print("completed mapping")

df_full = pd.DataFrame(list(results))

train = df_full[df_full.sponsored.notnull()].fillna(0)
test = df_full[df_full.sponsored.isnull() & df_full.file.isin(test_files)].fillna(0)

print("writing to csv")

train.to_csv('train_feats.csv', index=False)
test.to_csv('test_feats.csv', index=False)


from starlette.status import HTTP_200_OK
from .schemas import ResponseRegisterCashboxCharacter, \
    ResponseGetSystemID

doc_register_character = {
    'response_model': ResponseRegisterCashboxCharacter,
    'description': 'Регистрация символа кассы',
    'summary': 'Регистрация символа кассы',
    'response_description': 'Символ зарегистрирован успешно',
    'status_code': HTTP_200_OK,
}

doc_get_sys_id = {
    'response_model': ResponseGetSystemID,
    'description': 'Получение идентификатора устройства',
    'summary': 'Получение идентификатора устройства',
    'response_description': 'Идентификатор устройства',
    'status_code': HTTP_200_OK,
}
#
# doc_register_fiscal_cashier = {
#     'response_model': ResponseRegisterFiscalCashier,
#     'description': 'Регистрация кассира в фисальном регистраторе',
#     'summary': 'Регистрация кассира в фисальном регистраторе',
#     'response_description': 'Зарегистрирован успешно',
#     'status_code': HTTP_200_OK,
# }


# 4▹ Oblicz średnią arytmetyczną z kilku liczb. Liczby będą podane przez użytkownika po przecinku.
# Napisz funkcję, która przyjmie wartości i wyświetli średnią. Program powinien być odporny na błędy użytkownika.
# Błędów nie wyświetlaj, ale rodzaj błędu zapisz do pliku.

def user_input():
    user_input = ""
    user_input = input('Podaj liczby z których chcesz wyliczyć średnią arytmetyczną po przecinku: ')
    user_input = user_input.replace(' ', '').split(',')

    return user_input

def save_file(filename, content):
    try:
        with open(filename, 'x', encoding='UTF-8') as file:
            file.write(content)
    except FileExistsError:
        return 'not saved, file already exist'

    return 'file successfully saved'

def input_validation(user_input):
    number_list = []

    for item in user_input:
        try:
            item = int(item)
            number_list.append(item)
        except (ValueError, TypeError) as err:
            item = 0
            number_list.append(item)
            save_file("error.txt", err)

    return number_list

def calculate_average(number_list):
    user_input_avg = sum(number_list) / len(number_list)
    return user_input_avg

if __name__ == "__main__":
    number_list = input_validation(user_input())
    user_input_avg = calculate_average(number_list)
    print(f"Średnia z podanych liczb {number_list} to: {user_input_avg}")


import numpy as np
import tensorflow as tf
data = np.loadtxt('data/water.csv', skiprows=1, delimiter=',')
# print(data)
xdata = data[:, 1:-1]
ydata = data[:, -1:]
# print(xdata)
# print(ydata)
x = tf.placeholder(tf.float32, [None, 2])
y = tf.placeholder(tf.float32, [None, 1])
w = tf.Variable(tf.random_normal([2, 1]))
b = tf.Variable(tf.random_normal([1]))
h = tf.matmul(x, w) + b
cost = tf.reduce_mean(tf.square(y-h))
train = tf.train.GradientDescentOptimizer(0.00000000003).minimize(cost)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(3001):
        sess.run(train, feed_dict={x: xdata, y: ydata})
        if i % 1000 == 0:
            print(sess.run(cost, feed_dict={x: xdata, y: ydata}))
    print('예측 as시간', sess.run(h, feed_dict={x: [[70000, 230000]]}))
    ㅂ


import pandas as pd
import seaborn

seaborn.set()

print ('Reading race-result-horse.csv...')
df = pd.read_csv('data/race-result-horse.csv',
                 na_values=['DISQ', 'DNF', 'FE', 'PU', 'TNP', 'UR', 'VOID', 'WR', 'WV', 'WV-A', 'WX', 'WX-A', 'nan'])

print ('Reading race-result-race.csv...')
df2 = pd.read_csv('data/race-result-race.csv')

print ("Dropping non-integer finishing-positions...")
df = df.dropna(subset=['finishing_position'])
df['finishing_position'] = df['finishing_position'].replace([' DH'], '', regex=True)

print ("Creating new columns...")
df['recent_6_runs'] = 'NA'
df['recent_ave_rank'] = 7
df['horse_index'] = 'NA'
df['jockey_index'] = 'NA'
df['trainer_index'] = 'NA'
df['jockey_ave_rank'] = 7
df['trainer_ave_rank'] = 7
df['race_distance'] = 'NA'
df['race_course'] = 'NA'
df['race_class'] = 'NA'
df['track'] = 'NA'
df['track_condition'] = 'NA'
df['horse_win'] = 0
df['horse_rank_top_3'] = 0
df['horse_rank_top_50_percent'] = 0

print ("Generating lists of races, horses, jockeys and trainers...")
race_ids = []
id_list = []
jockey_list = []
trainer_list = []
idx = 0

for id in df['race_id'].values:
    if id not in race_ids:
        race_ids.append(id)

for id in df['horse_name'].values:
    if id not in id_list:
        id_list.append(id)

for name in df['jockey'].values:
    if name not in jockey_list:
        jockey_list.append(name)

for name in df['trainer'].values:
    if name not in trainer_list:
        trainer_list.append(name)

print ("Number of horses: ", len(id_list))
print ("Number of jockeys: ", len(jockey_list))
print ("Number of trainers: ", len(trainer_list))

print ("Adding racecourse information...")
for id in race_ids:
    df.loc[df.race_id == id, 'race_distance'] = df2.loc[df2.race_id == id, 'race_distance'].item()
    df.loc[df.race_id == id, 'race_course'] = df2.loc[df2.race_id == id, 'race_course'].item()
    df.loc[df.race_id == id, 'race_class'] = df2.loc[df2.race_id == id, 'race_class'].item()
    df.loc[df.race_id == id, 'track'] = df2.loc[df2.race_id == id, 'track'].item()
    df.loc[df.race_id == id, 'track_condition'] = df2.loc[df2.race_id == id, 'track_condition'].item()

print ("Adding horse statistics (index, rank, recent avg and results)...")
for id in id_list:
    df.loc[df['horse_id'] == id, 'horse_index'] = idx
    idx += 1

    breaker = '/'
    recent = []
    for index, record in df[df['horse_id'] == id].iterrows():
        pos = int(record.finishing_position)
        if pos == 1:
            df.loc[index, 'horse_win'] = 1
            df.loc[index, 'horse_rank_top_3'] = 1
            df.loc[index, 'horse_rank_top_50_percent'] = 1
        elif pos <= 3:
            df.loc[index, 'horse_rank_top_3'] = 1
            df.loc[index, 'horse_rank_top_50_percent'] = 1
        else:
            num_horses = max(map(float,df.loc[df['race_id'] == record.race_id, 'finishing_position']))
            if float(pos) / num_horses <= 0.5:
                df.loc[index, 'horse_rank_top_50_percent'] = 1

        if (len(recent)) != 0:
            df.loc[index, 'recent_ave_rank'] = sum(map(float,recent))/float(len(recent))

        df.loc[index, 'recent_6_runs'] = breaker.join(recent)
        recent.append(record.finishing_position)
        if len(recent) > 6:
            recent = recent[1:]

print ("Adding jockey statistics (index, avg rank)...")
idx = max(idx, 20000)
for name in jockey_list:
    df.loc[df.jockey == name, 'jockey_index'] = idx
    idx += 1
    jockey_record = df.loc[df.jockey == name]
    jockey_position = jockey_record.loc[df.race_id <= '2016-327', 'finishing_position']
    if len(jockey_position) != 0:
        df.loc[df.jockey == name, 'jockey_ave_rank'] = \
            sum(map(float, jockey_position))/float(len(jockey_position))

print ("Adding trainer statistics (index, avg rank)...")
idx = max(idx, 40000)
for name in trainer_list:
    df.loc[df.trainer == name, 'trainer_index'] = idx
    idx += 1
    trainer_record = df.loc[df.trainer == name]
    trainer_position = trainer_record.loc[df.race_id <= '2016-327', 'finishing_position']
    if len(trainer_position) != 0:
        df.loc[df.trainer == name, 'trainer_ave_rank'] = \
            sum(map(float, trainer_position))/float(len(trainer_position))

print ("Creating training.csv and testing.csv files...")
df_train = df.loc[df.race_id <= '2016-327']
df_test = df.loc[df.race_id > '2016-327']

df_train.to_csv('data/training.csv')
df_test.to_csv('data/testing.csv')

print ("Complete!")


# -*- coding: utf-8 -*-
"""
Created on Fri Jun 24 15:28:31 2022
@author: Richard Frazin

This is a module containing functions for sampling from a
power spectral density (PSD).  There are tools for 1D and 2D.
This is intended for modeling surface errors on the optics.
It will be assumed that there are no amplitude effects, so
the height variations are real-valued, making the Fourier
transforms Hermitian.
"""

import numpy as np
from scipy.integrate import quad
import cupy as cp

"""
Normal PSD fucntion (1D)
Fmax - the largest spatial frequency - the frequency grid goes from
    0 to +Fmax  (Kmax = 2piFmax)
h - the height of Gaussian
c - center
S - the width (std) of the Gaussian
n - the number of sampling points
"""
def MyGaussian1D(Fmax, h, c, sig, n):
    s = np.linspace(0, Fmax, n)
    f = np.zeros(s.shape)
    for k in range(len(s)):
        f[k] = h*np.exp(- (s[k] - c)**2/(2*sig*sig) )
    return(f)

"""
This surface roughness function is from Jhen Lumbres' thesis.
sigSR has units of nm
The default values for Kmax and Kmin are:
   Kmax = 1/(2.5 um) = 4.e-4 nm^-1 and
   Kmin = 1/(85 um) = 1.1765e-5 nm^-1, resp.
The output units are nm^2m^2
"""
def BetaSR(sigSR, Kmin=1.1765e-5, Kmax=4.0e-4):
    return( (sigSR*sigSR/np.pi)/(Kmax*Kmax - Kmin*Kmin) )

"""
Jhen's surface PSDs are given my sums of von Karman functions
k - spatial wavenumber (1/m)
beta - not sure what it means, but we need it.
inS - inner scale length (l0)
otS - outer scale length (L0)
sigSR - see BetaSR function
Kmin - see BetaSR function
Kmax - see BetaSR function
"""
def VonKarmanPSD(k, beta, inS, otS, alpha, sigSR, Kmin=1.1765e4, Kmax=4.0e5):
    ak = np.abs(k)
    betasr = BetaSR(sigSR, Kmin, Kmax)
    ex = np.exp(- (ak*inS)**2 )
    denom = ( 1/(otS*otS) + ak*ak )**(alpha/2)
    return(betasr + beta*ex/denom)

"""
Jhen's surface PSDs are given by sums of von Karman functions.
This function calls VonKarmanPSD in order to sum them up.
k - spatial wavenumber (units m^-1)
amp - list of a_0 values (usually 1)
beta - list of beta values
inS - list of inner scale values
otS - list of outer scale values
alpha - list of alpha values
sigSr - list of sigSR values
"""
def sumVonKarmanPSD(k, amp, beta, inS, otS, alpha, sigSR, base=1.e-9):
    assert (len(amp) == len(beta) == len(inS) == len(otS) == len(alpha) == len(sigSR))
    psd = base
    for l in range(len(beta)):
        psd += amp[l]*VonKarmanPSD(k, beta[l], inS[l], otS[l], alpha[l], sigSR[l])
    return(psd)
"""
This integrates the 1D or 2D PSD to get the RMS as a function of the maximum spatial
  frequency considered [Kmax - this has nothing to with Kmax in the function
  VonKarmanPSD()].  Kmin sets the lower limit of the integration.

In order to transform the integral to (natural) log space, where q = log(k),
  we first have to make a change of variables.
  For a 1D PSF (not a radial PSF, but a truly 1D object):
    Let f1(k) be the 1D PSD (which we do not have from the MagAO-X team)
    and let g1(q) be the 1D PSD in log space.  Then, the required change of
    variables is given by the condition    f1(k) dk = g1(q) dq -> g1(q) = f1(k)|dk/dq|
  For a 2D radial PSF:
    Let f2(k) be the 2D radial PSF where k^2 = kx^2 + ky^2 and let g2(q) be the 2D PSD in log space
    We can find g2(q) via the condition f2(k) k dk = g2(q) q dq -->
             g2(q) = f2(k) (k/q) |dk/dq| -> g2(q) = f2(exp(q)) (1/q) exp(2q)

Note that in 1D: RMS^2(Kmax) = 2*int_Kmin^Kmax f1(k) dk  (Kmin, Kmax  > 0)
                           = 2*int_{log(Kmin)}^{log(Kmax)} f1(exp(q)) exp(q) dq,
    In 2D:  RMS^2(Kmax) = 2pi*int_Kmin^Kmax f2(k) k dk
                        = 2pi*int_{log(Kmin)}^{log(Kmax)} f2(exp(q)) exp(2q) dq
Since k ranges over orders of magnitude, the log form the integral seems
    more suited to the problem.
Note that the units of k are [1/meters] so 1/(2.5 cm) = (1/0.025 m) = 40 m^-1
fcn  is a function handle that provides access to the function to be integrated.
    It is probably most convenient to make this a Python 'lambda' function
npts - the number of Kmax points
maxKmax - is the Kmax value for the last integration
Kmin - smallest spatial frequency considered in the integral
"""
def integrateLog(fcn, npts=100, maxKmax=2.e4, Kmin=4., ndim=2):
    assert ( (ndim == 1) or (ndim == 2) )
    lowlim = np.log(Kmin)  #  lower limit of integration
    logKmax = np.linspace(np.log(Kmin), np.log(maxKmax), npts)  # integration end points
    if ndim == 1:
        f = lambda t:       2*np.exp(  t)*fcn(np.exp(t))
    else:
        f = lambda t: 2*np.pi*np.exp(2*t)*(fcn(np.exp(t)))
    RMSsq = np.zeros((npts,))
    natLog2Log10 = np.log10(np.e)  # factor to convert natural logs to 10-based logs
    for nn in (1 + np.arange(npts-1)):
        RMSsq[nn] = quad(f, lowlim, logKmax[nn])[0]
    RMSsq[0] = RMSsq[1]  # don't want the first value to be zero

    return((RMSsq, natLog2Log10*logKmax))

"""
This samples a PSD from an input sequence assuming an
  exponential pdf: p(s) = (1/q)exp(-s/q) where q is the mean
psd - the input PSD -- only positive spatial frequencies!
L - length of the segment (centered on zero)
Fmax - max spatial frequency of psd
n - the number of points in the segment
"""
#def SampleExpPSD1D(psd, Fmax, L, n):
#    lp = len(psd)
#    f = np.linspace(0, Fmax, lp)  # spatial freq grid
#    x = np.linspace(-L/2, L/2, n)
#    surf = np.zeros(x.shape)
#    for k in (1 + np.arange(lp-1)): #don't include 0 spatial freq

#        pwr = np.random.exponential(psd[k])  ^^^ need to include "the dK"

#        camp = np.sqrt(pwr)*np.exp(1j*2*np.pi*np.random.rand())
#        ramp = np.real(camp)
#        iamp = np.imag(camp)
#        kf = 2*np.pi*f[k]  # spatial wavenumber
#        surf += 2*( ramp*np.cos(kf*x) + iamp*np.sin(kf*x) )
#    return(surf)

"""
This is similar to SampleExpPSD1D, except that is it 2D.
psd - the input psd - assumed to a radial function.
     -  units assumed to be nm^2 m^2
R - the radius of the surface (units meters)
gridspace - spacing of grid points on surface (units meters)
Kmin - minimum spatial frequency (units 1/m)
Kmax - maximum spatial frequency (units 1/m)
     - make sure this is resolved in terms of the gridspace parameter
dK - spatial fequency imcrement
"""
def SampleExpPSD2D(psd, R, gridspace, Kmin, Kmax, dK, useCUPY=False):
    if useCUPY:
        pp = cp
    else:
        pp = np
    #create spatial grid
    qq = pp.linspace(-R, R, int(2*R/gridspace))
    qq = pp.meshgrid(qq, qq)
    x = qq[0]; y = qq[1];  # x and y are 2D arrays of the spatial coords
    circle = pp.ones(x.shape)
    nk = x.shape[0]
    for l in range(nk):
        for m in range(nk):
            if x[m,l]**2 + y[m,l]**2 > R*R:
                circle[m,l] = 0.
    surf = pp.zeros(x.shape)  # random error surface
    #create spatial frequency grid
    qq = pp.linspace(-Kmax, Kmax, int(2*Kmax/dK))
    qq = pp.meshgrid(qq,qq)
    u = qq[0]; v = qq[1]  # u and v are 2D array of the spatial frequencies
    del(qq)
    nk = u.shape[0]  # length of spatial frequency grid
    tp = 2*pp.pi
    for l in range(nk):
        for m in range(int(nk/2)):  # only consider the lower 1/2 of the freq plane - this is where we implicitly assume the surface error is real-valued
            ak = pp.sqrt(v[m,l]**2 + u[m,l]**2)  # |k|
            if ( (ak < Kmin) or (ak > Kmax)):
                continue
            cf = pp.cos(tp*u[m,l]*x + tp*v[m,l]*y)
            sf = pp.sin(tp*u[m,l]*x + tp*v[m,l]*y)
            pwr = pp.random.exponential(psd(ak))*dK*dK
            camp = pp.sqrt(pwr)*pp.exp(1j*2*pp.pi*pp.random.rand())  # complex amplitude
            ramp = pp.real(camp)
            iamp = pp.imag(camp)
            surf += 2*(ramp*cf + iamp*sf)
    surf *= circle
    if useCUPY:
        surf = cp.asnumpy(surf)
    return(surf)

"""
This loads Jhen's PSD parameters
"""
#OAP PSDs - output units are nm^2m^2
params = {'OAP5':
  {'amp': [1., 1., 1.],
   'alpha': [3.029, -3.103, 0.668],
   'beta': [329.3, 1.6e-12, 3.49e-5],  # units are nm*m
    'otS': [0.019, 16., 0.024],  # units are m
    'inS': [-3.e-6, 4.29e-3, 1.32e-4],  # units are m
   'sigSR': [5.e-6, 5.e-6, 5.5e-1],  # units are nm
   'base': 1.e-9  # units nm^2m^2
  },'flat' :  # 50 mm flats, used for fold mirrors
   {'amp': [1., 1., 1.],
    'alpha': [3.284, 1.947, 2.827],
    'beta': [1180., 0.02983 , 44.25],  # units are nm*m
    'otS': [-0.017,-15., -5.7e-4],  # units are m
    'inS': [0.0225, 0.00335, 2.08e-4],  # units are m
    'sigSR': [5.e-5, 5.e-5, 0.08],  # units are nm
    'base': 1.e-10  # units nm^2m^2
    },'M3' :  # big telescope tertiary mirror
   {'amp': [1., 1., 0.],
    'alpha': [-27.924, 3.615, 0.],
    'beta': [1.261e-10, 65.27 , 0.],  # units are nm*m
    'otS': [0.42, 0.12, np.inf],  # units are m
    'inS': [-1.31, 8.81e-5, 0.],  # units are m
    'sigSR': [0.05, 0.37, 0.],  # units are nm
    'base': 2.3e-5  # units nm^2m^2
    }
}