import pandas as pd
import seaborn as sns
from pathlib import Path
from post_processing_multi import *

tags = [""]
# predefined budgets
budget_shots = [
    [None],
    {
        50000,
        1000,
        333,
        500,
        250,
        166,
        125,
        100,
        83,
        55,
        41,
        33,
        27,
        500000,
        10000,
        3333,
        5000,
        2500,
        1666,
        1250,
        1000,
        833,
        555,
        416,
        333,
        277,
        5000000,
        100000,
        33333,
        50000,
        25000,
        16666,
        12500,
        10000,
        8333,
        5555,
        4166,
        3333,
        2777,
        50000000,
        1000000,
        333333,
        500000,
        250000,
        166666,
        125000,
        100000,
        83333,
        55555,
        41666,
        33333,
        27777,
        500000000,
        10000000,
        3333333,
        5000000,
        2500000,
        1666666,
        1250000,
        1000000,
        833333,
        555555,
        416666,
        333333,
        277777,
        5000000000,
        100000000,
        33333333,
        50000000,
        25000000,
        16666666,
        12500000,
        10000000,
        8333333,
        5555555,
        4166666,
        3333333,
        2777777,
    },
]

def relative_shots(training_sets, noise_levels, max_copies, shots_budget):
    """Returns relative shots with less shots for COI when shots budget is high enough.

    Args:
        training_sets (int): number of training sets.
        noise_levels (int):  number of  noise levels
        max_copies (int): number of copies considred
        shots_budget (int): total budget

    Returns:
        pandas DF: dataframe with shot budgets
    """
    if shots_budget != 0:
        CDR_shots = shots_budget // training_sets
        vnCDR_shots = CDR_shots // noise_levels
        CGVD_shots = shots_budget // training_sets
        storage = pd.DataFrame(
            {
                "VD": [shots_budget // 2] * (max_copies),
                "ZNE": [shots_budget // 2] + [shots_budget // 4] * (max_copies - 1),
                "CDR": [CDR_shots] + [CDR_shots // 2] * (max_copies - 1),
                "vnCDR": [vnCDR_shots] * (max_copies),
                "CGVD": [
                    base_cost // (copy + 1) // 2
                    for copy, base_cost in enumerate([CGVD_shots] * (max_copies))
                ],
                "UNITED": [
                    x // noise_levels
                    for x in [
                        base_cost // (copy + 1)
                        for copy, base_cost in enumerate([CGVD_shots] * (max_copies))
                    ]
                ],
                "copies": list(range(1, max_copies + 1)),
            }
        )
    else:
        storage = pd.DataFrame(
            {
                "VD": None,
                "ZNE": None,
                "CDR": [None] * 6,
                "vnCDR": [None] * 6,
                "CGVD": [None] * 6,
                "UNITED": [None] * 6,
                "copies": list(range(1, max_copies + 1)),
            }
        )
    return pd.melt(storage, id_vars=("copies"))

def relative_shots_table(
    training_sets, noise_levels, max_copies, shots_budget, swap_levels
):
    """Returns relative shots used by techniques with no optimizations or considerations. Includes
    swap nosie.

    Args:
        training_sets (int): number of training sets.
        noise_levels (int):  number of  noise levels
        max_copies (int): number of copies considred
        shots_budget (int): total budget
        swap_levels (int): number of swap noise levels

    Returns:
        pandas DF: dataframe with shot budgets
    """
    if shots_budget != 0:
        CDR_shots = shots_budget // training_sets
        vnCDR_shots = CDR_shots // noise_levels
        CGVD_shots = shots_budget // training_sets
        storage = pd.DataFrame(
            {
                "VD": [shots_budget] + [shots_budget // 2] * (max_copies - 1),
                "ZNE": [shots_budget // 2] + [shots_budget // 4] * (max_copies - 1),
                "CDR": [CDR_shots] + [CDR_shots // 2] * (max_copies - 1),
                "vnCDR": [vnCDR_shots] + [vnCDR_shots // 2] * (max_copies - 1),
                "CGVD": [CGVD_shots]
                + [
                    base_cost // (copy + 2) // 2
                    for copy, base_cost in enumerate([CGVD_shots] * (max_copies - 1))
                ],
                "UNITED": [vnCDR_shots]
                + [
                    x // noise_levels // 2
                    for x in [
                        base_cost // (copy + 2)
                        for copy, base_cost in enumerate(
                            [CGVD_shots] * (max_copies - 1)
                        )
                    ]
                ],
                "UNITED+": [vnCDR_shots // swap_levels]
                + [
                    x // noise_levels // 2 // swap_levels
                    for x in [
                        base_cost // (copy + 2)
                        for copy, base_cost in enumerate(
                            [CGVD_shots] * (max_copies - 1)
                        )
                    ]
                ],
                "copies": list(range(1, max_copies + 1)),
            }
        )
    else:
        storage = pd.DataFrame(
            {
                "VD": None,
                "ZNE": None,
                "CDR": None,
                "vnCDR": None,
                "CGVD": None,
                "UNITED": None,
                "copies": list(range(1, max_copies + 1)),
            }
        )
    return storage

def single_qubit_gate_length(layers, qubits):
    return layers * 6 * (qubits - 1)

def two_qubit_gate_length(layers, qubits):
    return layers * (qubits - 1)

def circuit_length(layers, qubits):
    """calculates circuit length

    Args:
        layers (int): number of layers in RQC
        qubits (int): number of qubtis in system

    Returns:
        int: decomposed circuit depth
    """
    e1 = layers * 6 * (qubits - 1)
    e2 = layers * (qubits - 1)
    return e1 + e2

def total_error_rates_normal(layers, qubits, factor=1):
    """Generates total error rate in standard numerical experiment.

    Args:
        layers (int): number of layers of RQC.
        qubits (int): number of qubits
        factor (float, optional): noise scaling factor. Defaults to 1.

    Returns:
        float: total error rate.
    """
    e1 = layers * 6 * (qubits - 1) * 0.0011 * factor
    e2 = layers * (qubits - 1) * 0.0021 * factor
    return e1 + e2

def load_multiple_files(
    Q,
    p,
    num_seeds,
    nlsp_list=[1, 2, 3],
    N=10,
    Nts=100,
    max_copies=6,
    tags=[""],
    density_matrices=False,
    shots=[None],
    folder="",
    train=True,
):
    """Loads multiple files and processes all the data through the various techniques.

    Args:
        Q (list): list of qubits
        p (list): depth list, same length as Q
        num_seeds (int): number of seeds considered
        nlsp_list (list, optional): list of noise levels. Defaults to [1,2,3].
        N (int, optional): non clifford gates in simulation. Defaults to 10.
        Nts (int, optional): training set size. Defaults to 100.
        max_copies (int, optional): max number of copies in VD. Defaults to 6.
        tags (list, optional): list of additional tags. Defaults to [''].
        density_matrices (bool, optional): Do you have density matrices?. Defaults to False.
        shots (list, optional): shots of finite shot simulations. Defaults to [None].
        folder (str, optional): folder to be analyzed. Defaults to ''.
        train (bool, optional): existance of training data. Defaults to True.

    Returns:
        (absolute_error_df, error_rescaling_df, mitigated_values_df) : Various dfs of processed and organized data.
    """
    dfs_error_rescaling = []
    dfs_absolute_error = []
    dfs_standard_values = []
    for qubit_no, depth in zip(Q, p):
        print(f"Qubit: {Q}, depth: {p}")
        data_processing = VD_CDR(
            qubit_no,
            depth,
            num_seeds,
            N,
            Nts,
            max_copies,
            nlsp_list,
            shots=shots,
            folder=folder,
            autoprocessing=True,
            plots=False,
            density_matrices=density_matrices,
            extra_tags=tags,
            train=train,
        )

        dfs_absolute_error.append(
            data_processing.abs_error_df.assign(Qubits=qubit_no, depth=depth)
        )
        dfs_error_rescaling.append(
            data_processing.calculated_vals_df.assign(Qubits=qubit_no, depth=depth)
        )
        dfs_standard_values.append(
            data_processing.standard_df.assign(Qubits=qubit_no, depth=depth)
        )
    dfs_absolute_error = pd.concat(dfs_absolute_error)
    dfs_error_rescaling = pd.concat(dfs_error_rescaling)
    dfs_standard_values = pd.concat(dfs_standard_values)

    return dfs_absolute_error, dfs_error_rescaling, dfs_standard_values

def clean_data(maxcut_df):
    """cleans up data and assigns noisy data label to appropiate data,
    also puts converged values in appropiate places. This is just the high
    budget ZNE and Noisy values that converged already to infinity at 10**5."""
    noisy = maxcut_df.query(
        'abs_error > 0  & copies == 1 & nlsp==1 & res_type=="abs_error" & ( type=="VD")'
    )
    noisy["type"] = "noisy"
    extra = maxcut_df.query('Qubits==4&budget==10**12&(type=="VD"|type=="ZNE")')
    extra_vd = maxcut_df.query('budget==10**12& type=="VD" & copies==1')
    extra_noise = maxcut_df.query('budget==10**12& type=="VD" & copies==1')
    extra_vd["budget"] = 10 ** 10
    extra["budget"] = 10 ** 10
    extra_noise["budget"] = 10 ** 9
    return pd.concat([maxcut_df, extra, extra_vd, extra_noise])

def load_multiple_files_budget(
    Q,
    p,
    num_seeds,
    nlsp_list=[1, 2, 3],
    N=10,
    Nts=100,
    max_copies=6,
    tags=[""],
    density_matrices=False,
    shots=[[None]],
    folders=[""],
    train=True,
    budgets=[1],
    train_use=100,
):
    """Loads multiple files and processes all the data through the various techniques, assigns budget as well.
    But this needs to be further filtered.

    Args:
        Q (list): list of qubits
        p (list): depth list, same length as Q
        num_seeds (int): number of seeds considered
        nlsp_list (list, optional): list of noise levels. Defaults to [1,2,3].
        N (int, optional): non clifford gates in simulation. Defaults to 10.
        Nts (int, optional): training set size. Defaults to 100.
        max_copies (int, optional): max number of copies in VD. Defaults to 6.
        tags (list, optional): list of additional tags. Defaults to [''].
        density_matrices (bool, optional): Do you have density matrices?. Defaults to False.
        shots (list[lists], optional): list of lists of shots of finite shot simulations. Defaults to [[None]].
        folder (str, optional): folder to be analyzed. Defaults to ''.
        train (bool, optional): existance of training data. Defaults to True.
        budgets (list): list with same number of entries as shots lists corresponding to relative budget.
        train_use (int): how many trainig sets do you want to use?

    Returns:
        (absolute_error_df, error_rescaling_df, mitigated_values_df) : Various dfs of processed and organized data.
    """

    dfs_error_rescaling = []
    dfs_absolute_error = []
    dfs_standard_values = []
    for tag, folder in zip(tags, folders):
        print(tag)
        for budget_i, budget in enumerate(budgets):
            for qubit_no, depth in zip(Q, p):
                print(f"Qubit: {qubit_no}, depth: {depth}, budget:{budget}")
                # try:
                data_processing = VD_CDR(
                    qubit_no,
                    depth,
                    num_seeds,
                    N,
                    Nts,
                    max_copies,
                    nlsp_list,
                    shots=shots[budget_i],
                    folder=folder,
                    autoprocessing=True,
                    density_matrices=density_matrices,
                    extra_tags=[tag],
                    train=train,
                    budget=budget,
                    train_use=train_use,
                )
                dfs_absolute_error.append(
                    data_processing.abs_error_df.assign(
                        Qubits=qubit_no, depth=depth, budget=budget
                    )
                )
                dfs_error_rescaling.append(
                    data_processing.calculated_vals_df.assign(
                        Qubits=qubit_no, depth=depth, budget=budget
                    )
                )
                dfs_standard_values.append(
                    data_processing.standard_df.assign(
                        Qubits=qubit_no, depth=depth, budget=budget
                    )
                )
    dfs_absolute_error = pd.concat(dfs_absolute_error)
    dfs_error_rescaling = pd.concat(dfs_error_rescaling)
    dfs_standard_values = pd.concat(dfs_standard_values)
    return dfs_absolute_error, dfs_error_rescaling, dfs_standard_values

def filter_budget(df, budgets, training=100, max_copies=6, noise_levels=3):
    """Filters appropiate budget and shots for the technique in question.

    Args:
        df (result_df from load_multiple_files): Appropiate dataframe.
        budgets (list): list of budgets.
        training_use (int): how many training samples are actually used.
        noise_levels (int): maximum number of noise levels considered.
        copies (int): maximum number of copies considered.

    Returns:
        filtered_dataframe: dataframe with correct shot count data for appropiate technique
    """

    filtered_dfs = []
    for budget_i, budget in enumerate(budgets):
        shot_budget = relative_shots(training, noise_levels, max_copies, budget)
        for deets in shot_budget.iterrows():
            copy_no = deets[1][0]
            technique = deets[1][1]
            allowance = deets[1][2]
            if budget == 0:
                df_temp_abs = df.query(f"budget=={budget} & copies == {copy_no}")
            else:
                df_temp_abs = df.query(
                    f'type=="{technique}" & shots == {allowance} &  copies == {copy_no}'
                ).assign(budget=budget)
            filtered_dfs.append(df_temp_abs)
    filtered_dfs = pd.concat(filtered_dfs)

    return filtered_dfs

def load_max_cut_data(qubit_number: int, training_set=100):
    from pathlib import Path

    if Path("./MaxCut_runs/full_data_MC{qubit_number}.pq").is_file():
        Q = pd.read_parquet(f"./MaxCut_runs/full_data_MC{qubit_number}.pq")
    else:
        base_folder = f"./MaxCut_runs/Q{qubit_number}/"
        folders = [base_folder + ""]
        tags = [""]
        Q, _, _ = load_multiple_files_budget(
            [qubit_number],
            [0],
            29,
            nlsp_list=[1, 2, 3],
            N=10,
            Nts=training_set,
            max_copies=6,
            tags=tags,
            density_matrices=False,
            shots=budget_shots,
            folders=folders,
            train=True,
            budgets=[0, 1],
            train_use=100,
        )

        Q = Q.assign(description="3nlsp_full")
        Q.to_parquet(f"./MaxCut_runs/full_data_MC{qubit_number}.pq")
    Q_filtered = (
        filter_budget(
            Q, [0, 10 ** 5, 10 ** 6, 10 ** 7, 10 ** 8, 10 ** 9, 10 ** 10], 100
        )
        .drop(["shots"], axis=1)
        .query("abs_error>0")
    )

    ###
    Q_filtered.loc[Q_filtered["budget"] == 0, "budget"] = 10 ** 12
    ### Only done for plotting purposes, so that infinity is at the end of the plot rather than the start
    return Q_filtered

def figure_5(df, statistic_to_plot="mean"):
    """Plots figure five, which is the performance of the techniques over budget. This is extended in the sense that it returns
    all qubit results in a panel."""
    zero_copy_methods = df.query(
        'abs_error > 0  & copies == 1 & nlsp==1 & description == "3nlsp_full" & res_type=="abs_error" & ( type == "ZNE" | type == "vnCDR")'
    )
    noisy = df.query(
        'abs_error > 0  & copies == 1 & nlsp==1 & description == "3nlsp_full" & res_type=="abs_error" & ( type=="VD")'
    )
    few_copy_methods = df.query(
        'abs_error >  0  & nlsp==1 & copies==2 & description == "3nlsp_full" & res_type=="abs_error" & ( type=="VD")'
    )
    many_copy_methods = df.query(
        'abs_error > 0  &nlsp==1  & copies==4 & description == "3nlsp_full" & res_type=="abs_error" & ( type=="UNITED")'
    )
    noisy["type"] = "noisy"
    plot_df = pd.concat(
        [noisy, zero_copy_methods, few_copy_methods, many_copy_methods],
        axis=0,
        ignore_index=True,
    )
    fig = sns.relplot(
        data=plot_df.reset_index(),
        kind="line",
        x="budget",
        y="abs_error",
        hue="type",
        col="Qubits",
        col_wrap=2,
        estimator=statistic_to_plot,
        markers=True,
        ci=None,
    )
    fig.set(yscale="log", xscale="log")
    fig.set_ylabels(statistic_to_plot + " of absolute error")
    ax = fig.axes[0]
    xticks = ax.get_xticks().tolist()
    for i in range(len(xticks) - 1):
        xticks[i] = rf"$10^{{{i+3}}}$"
    xticks[-3] = r"$\infty$"
    xticks[-4] = r"$\cdots$"
    ax.set_xticklabels(xticks)
    return fig

def figure_4(maxcut_df, statistic_to_plot="mean", like_paper=True):
    """"Plot figure 5 from the paper, which is the absoulte error over qubits at different budgets."""
    if like_paper:
        df = maxcut_df.query("budget>0&budget<10**11&budget!=10**9&budget!=10**7")
    else:  # Basically will show all computed budgets
        df = maxcut_df.query("budget>0&budget<10**11")
    zero_copy_methods = df.query(
        'abs_error > 0  & copies == 1 & nlsp==1 & description == "3nlsp_full" & res_type=="abs_error" & ( type == "ZNE" | type == "vnCDR")'
    )
    noisy = df.query(
        'abs_error > 0  & copies == 1 & nlsp==1 & description == "3nlsp_full" & res_type=="abs_error" & ( type=="VD")'
    )
    few_copy_methods = df.query(
        'abs_error >  0  & nlsp==1 & copies==2 & description == "3nlsp_full" & res_type=="abs_error" & ( type=="VD")'
    )
    many_copy_methods = df.query(
        'abs_error > 0  &nlsp==1  & copies==4& description == "3nlsp_full" & res_type=="abs_error" & ( type=="UNITED")'
    )
    noisy["type"] = "noisy"
    plot_df = pd.concat(
        [noisy, zero_copy_methods, few_copy_methods, many_copy_methods],
        axis=0,
        ignore_index=True,
    )
    fig = sns.relplot(
        data=plot_df.reset_index(),
        kind="line",
        x="Qubits",
        col="budget",
        col_wrap=2,
        y="abs_error",
        hue="type",
        estimator=statistic_to_plot,
        markers=True,
        ci=None,
    )
    fig.set_ylabels(statistic_to_plot + " of absolute error")
    fig.set(yscale="log")
    return fig

def load_all_data():
    if Path("./MaxCut_runs/filtered_df.pq").is_file():
        maxcut_df = pd.read_parquet("./MaxCut_runs/filtered_df.pq")
    else:
        results = {qubit: load_max_cut_data(qubit) for qubit in [4, 6, 8, 10]}
        maxcut_df = pd.concat(results.values())
        maxcut_df = clean_data(maxcut_df)
        maxcut_df.to_parquet("./MaxCut_runs/filtered_df.pq")
    return maxcut_df

def load_unfiltered_data():
    dfs = []
    for i in [4, 6, 8, 10]:
        dfs.append(pd.read_parquet(f"./MaxCut_runs/full_data_MC{i}.pq"))
    return pd.concat(dfs).reset_index()

def load_raw_maxcut_data():
    """Returns a dictionary of the coi data and training data with indices 'coi' and 'train'."""
    import os

    def quick_load(fi, dir_path):
        res = []
        files = []
        for file in os.listdir(dir_path):
            if file.endswith(".pq") and file.startswith(f"pandas_{fi}"):
                res.append(
                    pd.read_parquet(dir_path + file).assign(file=file).assign(data=fi)
                )
                files.append(file)
        res = pd.concat(res)
        res = res.reset_index()
        res = res.reset_index()
        res = res.drop(["result_type"], axis=1)
        res["exact"] = pd.to_numeric(res["exact"])
        res["expectation"] = pd.to_numeric(res["expectation"])
        res["exact_abs"] = np.abs(res["exact"])
        return res

    train = []
    coi = []
    for i in [4, 6, 8, 10]:
        path = f"./MaxCut_runs/Q{i}/"
        train.append(quick_load("train", path))
        coi.append(quick_load("COI", path))
    train = pd.concat(train).reset_index().drop("level_0", axis=1)
    coi = pd.concat(coi).reset_index().drop("level_0", axis=1)
    return {"coi": coi, "train": train}

def figure_7(df, budget=10 ** 10, statistic_to_plot="mean"):
    """Plots figure 7 for any budget"""
    df = df.query(f"budget=={budget}")
    few_copy_methods = df.query(
        'abs_error >  0  & nlsp==1  & description == "3nlsp_full" & res_type=="abs_error" & ( type=="VD")'
    )
    many_copy_methods = df.query(
        'abs_error > 0  &nlsp==1  & description == "3nlsp_full" & res_type=="abs_error" & ( type=="UNITED")'
    )
    plot_df = pd.concat(
        [few_copy_methods, many_copy_methods], axis=0, ignore_index=True,
    )
    fig = sns.relplot(
        data=plot_df.reset_index(),
        kind="line",
        x="copies",
        y="abs_error",
        hue="Qubits",
        style="type",
        estimator=statistic_to_plot,
        ci=None,
    )
    fig.set(yscale="log", title=f"budget {budget}")
    fig.set_ylabels(statistic_to_plot + " of absolute error")
    return fig

def figure_8(dataset):
    """Plots the disctibution of training data and circuit of interest for desired qubit"""
    sns.displot(
        kind="hist",
        data=dataset,
        x="exact",
        col="qubits",
        col_wrap=2,
        bins=25,
        facet_kws=dict(sharey=True),
    ).set(yscale="log")


'''
#=============================================================================
#     FileName: app.py
#         Desc: project of one game that run on the web page
#       Author: Honglong Wu
#        Email: wuhonglong@genomics.cn
#      Version: 0.0.1
#      Created: 15/03/2015
#      History:
#=============================================================================
'''

#-*- coding: utf-8 -*-

import web

urls = (
  '/hello', 'Index'
)

app = web.application(urls, globals())

# absolute path not the relative path
render = web.template.render('/Users/user/bin/GitHub/LPHW/Ex50/gothonweb/templates/', base = "layout")

class Index(object):
	def GET(self):
		return render.hello_form()

	def POST(self):
		form = web.input(greet=None, name = "Nobody")
		greet = "%s, %s" % (form.greet, form.name)
		return render.index(greeting = greet)

if __name__ == "__main__":
	app.run()


from argparse import ArgumentParser, Namespace
from copy import deepcopy

import torch

from fedavg import FedAvgServer, get_fedavg_argparser
from src.client.fedfomo import FedFomoClient

def get_fedfomo_argparser() -> ArgumentParser:
    parser = get_fedavg_argparser()
    parser.add_argument("--M", type=int, default=5)
    parser.add_argument("--valset_ratio", type=float, default=0.2)
    return parser

class FedFomoServer(FedAvgServer):
    def __init__(
        self,
        algo: str = "FedFomo",
        args: Namespace = None,
        unique_model=True,
        default_trainer=False,
    ):
        if args is None:
            args = get_fedfomo_argparser().parse_args()
        super().__init__(algo, args, unique_model, default_trainer)
        self.trainer = FedFomoClient(
            deepcopy(self.model), self.args, self.logger, self.device, self.client_num
        )
        self.P = torch.eye(self.client_num, device=self.device)

    def train_one_round(self):
        client_params_cache = []
        for client_id in self.selected_clients:
            selected_params = self.generate_client_params(client_id)

            (
                client_params,
                weight_vector,
                self.client_stats[client_id][self.current_epoch],
            ) = self.trainer.train(
                client_id=client_id,
                local_epoch=self.clients_local_epoch[client_id],
                received_params=selected_params,
                verbose=((self.current_epoch + 1) % self.args.verbose_gap) == 0,
            )

            client_params_cache.append(client_params)
            self.P[client_id] += weight_vector

        self.update_client_params(client_params_cache)

    @torch.no_grad()
    def generate_client_params(self, client_id):
        prev_round_clients = self.client_sample_stream[self.current_epoch - 1]
        selected_params = {}
        if not self.test_flag and self.current_epoch > 0:
            selected_params = {
                prev_round_clients[i]: self.client_trainable_params[
                    prev_round_clients[i]
                ]
                for i in torch.topk(
                    self.P[client_id][prev_round_clients], self.args.M
                ).indices.tolist()
            }
        selected_params[client_id] = self.client_trainable_params[client_id]
        return selected_params

if __name__ == "__main__":
    server = FedFomoServer()
    server.run()


import cv2 as cv
from cv2 import aruco
import numpy as np

marker_dict = aruco.Dictionary_get(aruco.DICT_4X4_50)

param_markers = aruco.DetectorParameters_create()
cap = cv.VideoCapture(0)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    marker_corners, marker_IDs, reject = aruco.detectMarkers(
        frame, marker_dict, parameters = param_markers
        )
    if marker_corners:
        for ids, corners in zip(marker_IDs, marker_corners):
            cv.polylines(frame, [corners.astype(np.int32)], True, (0, 244, 28), 4, cv.LINE_AA)

            corners = corners.reshape(4,2)
            corners = corners.astype(int)
            top_right = corners.ravel()
            cv.putText(frame, f'id: {ids[0]}', top_right,
                cv.FONT_HERSHEY_COMPLEX, 1.3, (0,255,23), 2, cv.LINE_AA)

            #print(ids,"  ", corners)

    cv.imshow('frame', frame)
    key = cv.waitKey(1)  #take the input form the keyboard
    if key == ord('q'):  # convert the input into uni-code
        break

cap.release()
cv.destroyAllWindows()


#!/usr/bin/env python3

from typing import no_type_check, Optional, Tuple

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch import Tensor

"""
@no_type_check annotation is applied to type-hinted models to avoid errors
related to mismatch with parent (nn.Module) signature. # type_ignore is not
possible here, since it causes errors in JIT scripting code which parses
the relevant type hints.
"""

class BasicLinearReLULinear(nn.Module):
    def __init__(self, in_features, out_features=5, bias=False) -> None:
        super().__init__()
        self.fc1 = nn.Linear(in_features, out_features, bias=bias)
        self.relu1 = nn.ReLU()
        self.fc2 = nn.Linear(out_features, 1, bias=bias)

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu1(x)
        x = self.fc2(x)
        return x

class MixedKwargsAndArgsModule(nn.Module):
    def __init__(self) -> None:
        super().__init__()

    def forward(self, x, y=None):
        if y is not None:
            return x + y
        return x

class BasicModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()

    def forward(self, input):
        input = 1 - F.relu(1 - input)
        return input

class BasicModel2(nn.Module):
    """
    Example model one from the paper
    https://arxiv.org/pdf/1703.01365.pdf

    f(x1, x2) = RELU(ReLU(x1) - 1 - ReLU(x2))
    """

    def __init__(self) -> None:
        super().__init__()

    def forward(self, input1, input2):
        relu_out1 = F.relu(input1)
        relu_out2 = F.relu(input2)
        return F.relu(relu_out1 - 1 - relu_out2)

class BasicModel3(nn.Module):
    """
    Example model two from the paper
    https://arxiv.org/pdf/1703.01365.pdf

    f(x1, x2) = RELU(ReLU(x1 - 1) - ReLU(x2))
    """

    def __init__(self) -> None:
        super().__init__()

    def forward(self, input1, input2):
        relu_out1 = F.relu(input1 - 1)
        relu_out2 = F.relu(input2)
        return F.relu(relu_out1 - relu_out2)

class BasicModel4_MultiArgs(nn.Module):
    """
    Slightly modified example model from the paper
    https://arxiv.org/pdf/1703.01365.pdf
    f(x1, x2) = RELU(ReLU(x1 - 1) - ReLU(x2) / x3)
    """

    def __init__(self) -> None:
        super().__init__()

    def forward(self, input1, input2, additional_input1, additional_input2=0):
        relu_out1 = F.relu(input1 - 1)
        relu_out2 = F.relu(input2)
        relu_out2 = relu_out2.div(additional_input1)
        return F.relu(relu_out1 - relu_out2)[:, additional_input2]

class BasicModel5_MultiArgs(nn.Module):
    """
    Slightly modified example model from the paper
    https://arxiv.org/pdf/1703.01365.pdf
    f(x1, x2) = RELU(ReLU(x1 - 1) * x3[0] - ReLU(x2) * x3[1])
    """

    def __init__(self) -> None:
        super().__init__()

    def forward(self, input1, input2, additional_input1, additional_input2=0):
        relu_out1 = F.relu(input1 - 1) * additional_input1[0]
        relu_out2 = F.relu(input2)
        relu_out2 = relu_out2 * additional_input1[1]
        return F.relu(relu_out1 - relu_out2)[:, additional_input2]

class BasicModel6_MultiTensor(nn.Module):
    def __init__(self) -> None:
        super().__init__()

    def forward(self, input1, input2):
        input = input1 + input2
        return 1 - F.relu(1 - input)[:, 1]

class BasicLinearModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.linear = nn.Linear(7, 1)

    def forward(self, x1, x2):
        return self.linear(torch.cat((x1, x2), dim=-1))

class BasicLinearModel2(nn.Module):
    def __init__(self, in_features, out_features) -> None:
        super().__init__()
        self.linear = nn.Linear(in_features, out_features, bias=False)

    def forward(self, input):
        return self.linear(input)

class BasicLinearModel_Multilayer(nn.Module):
    def __init__(self, in_features, hidden_nodes, out_features) -> None:
        super().__init__()
        self.linear1 = nn.Linear(in_features, hidden_nodes, bias=False)
        self.linear2 = nn.Linear(hidden_nodes, out_features, bias=False)

    def forward(self, input):
        x = self.linear1(input)
        return self.linear2(x)

class ReLUDeepLiftModel(nn.Module):
    r"""
    https://www.youtube.com/watch?v=f_iAM0NPwnM
    """

    def __init__(self) -> None:
        super().__init__()
        self.relu1 = nn.ReLU()
        self.relu2 = nn.ReLU()

    def forward(self, x1, x2, x3=2):
        return 2 * self.relu1(x1) + x3 * self.relu2(x2 - 1.5)

class LinearMaxPoolLinearModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        # kernel size -> 4
        self.lin1 = nn.Linear(4, 4, bias=False)
        self.lin1.weight = nn.Parameter(torch.eye(4, 4))
        self.pool1 = nn.MaxPool1d(4)
        self.lin2 = nn.Linear(1, 1, bias=False)
        self.lin2.weight = nn.Parameter(torch.ones(1, 1))

    def forward(self, x):
        x = x.unsqueeze(1)
        return self.lin2(self.pool1(self.lin1(x))[:, 0, :])

class BasicModelWithReusedModules(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.lin1 = nn.Linear(3, 2)
        self.relu = nn.ReLU()
        self.lin2 = nn.Linear(2, 2)

    def forward(self, inputs):
        return self.relu(self.lin2(self.relu(self.lin1(inputs))))

class BasicModelWithReusedLinear(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.lin1 = nn.Linear(3, 3)
        self.relu = nn.ReLU()

    def forward(self, inputs):
        return self.relu(self.lin1(self.relu(self.lin1(inputs))))

class BasicModelWithSparseInputs(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.lin1 = nn.Linear(3, 1)
        self.lin1.weight = nn.Parameter(torch.tensor([[3.0, 1.0, 2.0]]))
        self.lin1.bias = nn.Parameter(torch.zeros(1))

    def forward(self, inputs, sparse_list):
        return (
            self.lin1(inputs) + (sparse_list[0] if torch.numel(sparse_list) > 0 else 0)
        ).sum()

class BasicModel_MaxPool_ReLU(nn.Module):
    def __init__(self, inplace=False) -> None:
        super().__init__()
        self.maxpool = nn.MaxPool1d(3)
        self.relu = nn.ReLU(inplace=inplace)

    def forward(self, x):
        return self.relu(self.maxpool(x)).sum(dim=1)

class TanhDeepLiftModel(nn.Module):
    r"""
    Same as the ReLUDeepLiftModel, but with activations
    that can have negative outputs
    """

    def __init__(self) -> None:
        super().__init__()
        self.tanh1 = nn.Tanh()
        self.tanh2 = nn.Tanh()

    def forward(self, x1, x2):
        return 2 * self.tanh1(x1) + 2 * self.tanh2(x2 - 1.5)

class ReLULinearModel(nn.Module):
    r"""
    Simple architecture similar to:
    https://github.com/marcoancona/DeepExplain/blob/master/deepexplain/tests/test_tensorflow.py#L65
    """

    def __init__(self, inplace: bool = False) -> None:
        super().__init__()
        self.l1 = nn.Linear(3, 1, bias=False)
        self.l2 = nn.Linear(3, 1, bias=False)
        self.l1.weight = nn.Parameter(torch.tensor([[3.0, 1.0, 0.0]]))  # type: ignore
        self.l2.weight = nn.Parameter(torch.tensor([[2.0, 3.0, 0.0]]))  # type: ignore
        self.relu = nn.ReLU(inplace=inplace)
        self.l3 = nn.Linear(2, 1, bias=False)
        self.l3.weight = nn.Parameter(torch.tensor([[1.0, 1.0]]))  # type: ignore

    @no_type_check
    def forward(self, x1: Tensor, x2: Tensor, x3: int = 1) -> Tensor:
        return self.l3(self.relu(torch.cat([self.l1(x1), x3 * self.l2(x2)], dim=1)))

class SimpleLRPModel(nn.Module):
    def __init__(self, inplace) -> None:
        super().__init__()
        self.linear = nn.Linear(3, 3, bias=False)
        self.linear.weight.data.fill_(2.0)
        self.relu = torch.nn.ReLU(inplace=inplace)
        self.linear2 = nn.Linear(3, 1, bias=False)
        self.linear2.weight.data.fill_(3.0)
        self.dropout = torch.nn.Dropout(p=0.01)

    def forward(self, x):
        return self.dropout(self.linear2(self.relu(self.linear(x))))

class Conv1dSeqModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.seq = nn.Sequential(nn.Conv1d(4, 2, 1), nn.ReLU(), nn.Linear(1000, 1))

    def forward(self, inputs):
        return self.seq(inputs)

class TextModule(nn.Module):
    r"""Basic model that has inner embedding layer. This layer can be pluged
    into a larger network such as `BasicEmbeddingModel` and help us to test
    nested embedding layers
    """

    def __init__(self, num_embeddings, embedding_dim, second_embedding=False) -> None:
        super().__init__()
        self.inner_embedding = nn.Embedding(num_embeddings, embedding_dim)
        self.second_embedding = second_embedding
        if self.second_embedding:
            self.inner_embedding2 = nn.Embedding(num_embeddings, embedding_dim)

    def forward(self, input=None, another_input=None):
        assert input is not None, "The inputs to embedding module must be specified"
        embedding = self.inner_embedding(input)
        if self.second_embedding:
            another_embedding = self.inner_embedding2(
                input if another_input is None else another_input
            )
        return embedding if another_input is None else embedding + another_embedding

class BasicEmbeddingModel(nn.Module):
    r"""
    Implements basic model with nn.Embedding layer. This simple model
    will help us to test nested InterpretableEmbedding layers
    The model has the following structure:
    BasicEmbeddingModel(
      (embedding1): Embedding(30, 100)
      (embedding2): TextModule(
        (inner_embedding): Embedding(30, 100)
      )
      (linear1): Linear(in_features=100, out_features=256, bias=True)
      (relu): ReLU()
      (linear2): Linear(in_features=256, out_features=1, bias=True)
    )
    """

    def __init__(
        self,
        num_embeddings=30,
        embedding_dim=100,
        hidden_dim=256,
        output_dim=1,
        nested_second_embedding=False,
    ) -> None:
        super().__init__()
        self.embedding1 = nn.Embedding(num_embeddings, embedding_dim)
        self.embedding2 = TextModule(
            num_embeddings, embedding_dim, nested_second_embedding
        )
        self.linear1 = nn.Linear(embedding_dim, hidden_dim, bias=False)
        self.linear1.weight = nn.Parameter(torch.ones(hidden_dim, embedding_dim))
        self.relu = nn.ReLU()
        self.linear2 = nn.Linear(hidden_dim, output_dim)
        self.linear2.weight = nn.Parameter(torch.ones(output_dim, hidden_dim))

    def forward(self, input1, input2, input3=None):
        embedding1 = self.embedding1(input1)
        embedding2 = self.embedding2(input2, input3)
        embeddings = embedding1 + embedding2
        return self.linear2(self.relu(self.linear1(embeddings))).sum(1)

class MultiRelu(nn.Module):
    def __init__(self, inplace: bool = False) -> None:
        super().__init__()
        self.relu1 = nn.ReLU(inplace=inplace)
        self.relu2 = nn.ReLU(inplace=inplace)

    @no_type_check
    def forward(self, arg1: Tensor, arg2: Tensor) -> Tuple[Tensor, Tensor]:
        return (self.relu1(arg1), self.relu2(arg2))

class BasicModel_MultiLayer(nn.Module):
    def __init__(self, inplace=False, multi_input_module=False) -> None:
        super().__init__()
        # Linear 0 is simply identity transform
        self.multi_input_module = multi_input_module
        self.linear0 = nn.Linear(3, 3)
        self.linear0.weight = nn.Parameter(torch.eye(3))
        self.linear0.bias = nn.Parameter(torch.zeros(3))
        self.linear1 = nn.Linear(3, 4)
        self.linear1.weight = nn.Parameter(torch.ones(4, 3))
        self.linear1.bias = nn.Parameter(torch.tensor([-10.0, 1.0, 1.0, 1.0]))

        self.linear1_alt = nn.Linear(3, 4)
        self.linear1_alt.weight = nn.Parameter(torch.ones(4, 3))
        self.linear1_alt.bias = nn.Parameter(torch.tensor([-10.0, 1.0, 1.0, 1.0]))
        self.multi_relu = MultiRelu(inplace=inplace)
        self.relu = nn.ReLU(inplace=inplace)

        self.linear2 = nn.Linear(4, 2)
        self.linear2.weight = nn.Parameter(torch.ones(2, 4))
        self.linear2.bias = nn.Parameter(torch.tensor([-1.0, 1.0]))

    @no_type_check
    def forward(
        self,
        x: Tensor,
        add_input: Optional[Tensor] = None,
        multidim_output: bool = False,
    ):
        input = x if add_input is None else x + add_input
        lin0_out = self.linear0(input)
        lin1_out = self.linear1(lin0_out)
        if self.multi_input_module:
            relu_out1, relu_out2 = self.multi_relu(lin1_out, self.linear1_alt(input))
            relu_out = relu_out1 + relu_out2
        else:
            relu_out = self.relu(lin1_out)
        lin2_out = self.linear2(relu_out)
        if multidim_output:
            stack_mid = torch.stack((lin2_out, 2 * lin2_out), dim=2)
            return torch.stack((stack_mid, 4 * stack_mid), dim=3)
        else:
            return lin2_out

class BasicModelBoolInput(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.mod = BasicModel_MultiLayer()

    def forward(
        self,
        x: Tensor,
        add_input: Optional[Tensor] = None,
        mult: float = 10.0,
    ):
        assert x.dtype is torch.bool, "Input must be boolean"
        return self.mod(x.float() * mult, add_input)

class BasicModel_MultiLayer_MultiInput(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.model = BasicModel_MultiLayer()

    @no_type_check
    def forward(self, x1: Tensor, x2: Tensor, x3: Tensor, scale: int):
        return self.model(scale * (x1 + x2 + x3))

class BasicModel_MultiLayer_TrueMultiInput(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.m1 = BasicModel_MultiLayer()
        self.m234 = BasicModel_MultiLayer_MultiInput()

    @no_type_check
    def forward(
        self, x1: Tensor, x2: Tensor, x3: Tensor, x4: Optional[Tensor] = None
    ) -> Tensor:
        a = self.m1(x1)
        if x4 is None:
            b = self.m234(x2, x3, x1, scale=1)
        else:
            b = self.m234(x2, x3, x4, scale=1)
        return a + b

class BasicModel_ConvNet_One_Conv(nn.Module):
    def __init__(self, inplace: bool = False) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 2, 3, 1)
        self.relu1 = nn.ReLU(inplace=inplace)
        self.fc1 = nn.Linear(8, 4)
        self.conv1.weight = nn.Parameter(torch.ones(2, 1, 3, 3))  # type: ignore
        self.conv1.bias = nn.Parameter(torch.tensor([-50.0, -75.0]))  # type: ignore
        self.fc1.weight = nn.Parameter(  # type: ignore
            torch.cat([torch.ones(4, 5), -1 * torch.ones(4, 3)], dim=1)
        )
        self.fc1.bias = nn.Parameter(torch.zeros(4))  # type: ignore
        self.relu2 = nn.ReLU(inplace=inplace)

    @no_type_check
    def forward(self, x: Tensor, x2: Optional[Tensor] = None):
        if x2 is not None:
            x = x + x2
        x = self.relu1(self.conv1(x))
        x = x.view(-1, 8)
        return self.relu2(self.fc1(x))

class BasicModel_ConvNetWithPaddingDilation(nn.Module):
    def __init__(self, inplace: bool = False) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 2, 3, padding=3, stride=2, dilation=2)
        self.relu1 = nn.ReLU(inplace=inplace)
        self.fc1 = nn.Linear(16, 4)

    @no_type_check
    def forward(self, x: Tensor):
        bsz = x.shape[0]
        x = self.relu1(self.conv1(x))
        x = x.reshape(bsz, 2, -1)
        return self.fc1(x).reshape(bsz, -1)

class BasicModel_ConvNet(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 2, 3, 1)
        self.relu1 = nn.ReLU()
        self.pool1 = nn.MaxPool2d(2)
        self.conv2 = nn.Conv2d(2, 4, 3, 1)
        self.relu2 = nn.ReLU()
        self.pool2 = nn.MaxPool2d(2)
        self.fc1 = nn.Linear(4, 8)
        self.relu3 = nn.ReLU()
        self.fc2 = nn.Linear(8, 10)
        self.softmax = nn.Softmax(dim=1)

        self.fc1.weight = nn.Parameter(torch.ones(8, 4))
        self.fc2.weight = nn.Parameter(torch.ones(10, 8))

    @no_type_check
    def forward(self, x: Tensor) -> Tensor:
        x = self.relu1(self.conv1(x))
        x = self.pool1(x)
        x = self.relu2(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 4)
        x = self.relu3(self.fc1(x))
        x = self.fc2(x)
        return self.softmax(x)

class BasicModel_ConvNet_MaxPool1d(nn.Module):
    """Same as above, but with the MaxPool2d replaced
    with a MaxPool1d. This is useful because the MaxPool modules
    behave differently to other modules from the perspective
    of the DeepLift Attributions
    """

    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv1d(1, 2, 3)
        self.relu1 = nn.ReLU()
        self.pool1 = nn.MaxPool1d(2)
        self.conv2 = nn.Conv1d(2, 4, 3)
        self.relu2 = nn.ReLU()
        self.pool2 = nn.MaxPool1d(2)
        self.fc1 = nn.Linear(4, 8)
        self.relu3 = nn.ReLU()
        self.fc2 = nn.Linear(8, 10)
        self.softmax = nn.Softmax(dim=1)

        self.fc1.weight = nn.Parameter(torch.ones(8, 4))
        self.fc2.weight = nn.Parameter(torch.ones(10, 8))

    @no_type_check
    def forward(self, x: Tensor) -> Tensor:
        x = self.relu1(self.conv1(x))
        x = self.pool1(x)
        x = self.relu2(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 4)
        x = self.relu3(self.fc1(x))
        x = self.fc2(x)
        return self.softmax(x)

class BasicModel_ConvNet_MaxPool3d(nn.Module):
    """Same as above, but with the MaxPool1d replaced
    with a MaxPool3d. This is useful because the MaxPool modules
    behave differently to other modules from the perspective
    of the DeepLift Attributions
    """

    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv3d(1, 2, 3)
        self.relu1 = nn.ReLU()
        self.pool1 = nn.MaxPool3d(2)
        self.conv2 = nn.Conv3d(2, 4, 3)
        self.relu2 = nn.ReLU()
        self.pool2 = nn.MaxPool3d(2)
        self.fc1 = nn.Linear(4, 8)
        self.relu3 = nn.ReLU()
        self.fc2 = nn.Linear(8, 10)
        self.softmax = nn.Softmax(dim=1)

        self.fc1.weight = nn.Parameter(torch.ones(8, 4))
        self.fc2.weight = nn.Parameter(torch.ones(10, 8))

    def forward(self, x):
        x = self.relu1(self.conv1(x))
        x = self.pool1(x)
        x = self.relu2(self.conv2(x))
        x = self.pool2(x)
        x = x.view(-1, 4)
        x = self.relu3(self.fc1(x))
        x = self.fc2(x)
        return self.softmax(x)


import datetime

from django import template
from schedule.models import Calendar
from schedule.settings import CHECK_EVENT_PERM_FUNC, CHECK_CALENDAR_PERM_FUNC
from schedule.templatetags.scheduletags import _cook_slots

from good_spot.places.tasks import get_places_to_update

register = template.Library()

@register.inclusion_tag('proxy/templatetags/_updates_count.html', takes_context=True)
def updates_count(context, slot):
    context['count'] = get_places_to_update(slot.start, slot.end).count()
    return context

@register.inclusion_tag('schedule/_daily_table.html', takes_context=True)
def custom_daily_table(context, day, start=8, end=20, increment=30):
    """
      Display a nice table with occurrences and action buttons.
      Arguments:
      start - hour at which the day starts
      end - hour at which the day ends
      increment - size of a time slot (in minutes)
    """
    user = context['request'].user
    addable = CHECK_EVENT_PERM_FUNC(None, user)
    if 'calendar' in context:
        addable = addable and CHECK_CALENDAR_PERM_FUNC(context['calendar'], user)
    context['addable'] = addable
    day_part = day.get_time_slot(day.start + datetime.timedelta(hours=start), day.start + datetime.timedelta(hours=end))
    # get slots to display on the left
    slots = _cook_slots(day_part, increment)
    context['slots'] = slots
    return context

@register.inclusion_tag('proxy/templatetags/calendar_list.html')
def calendars_list():
    calendars = Calendar.objects.all()
    context = {
        "calendars": calendars
    }
    return context


from configparser import ConfigParser
import json
import os

from PyQt5 import QtGui, QtWidgets
from scipy import logspace, log10
from matplotlib.patches import ConnectionPatch
from matplotlib import image

from lib.config import conf_dir, IMAGE_PATH
from lib.friction import f_list, eD
from lib.plot import mpl
from lib.utilities import formatLine, representacion
from UI.prefMoody import ConfigDialog
from UI.widgets import Entrada_con_unidades

Re_laminar = [600, 2400]
Re_turbulent = logspace(log10(2400), 8, 50)
Re_fully = logspace(log10(4000), 8, 50)

def calculate(config):
    fanning = config.getboolean("Moody", "fanning")
    method = config.getint("Moody", "method")
    eD = eval(config.get("Moody", "eD"))
    F = f_list[method]

    dat = {}
    dat["fanning"] = fanning
    dat["method"] = method
    # laminar
    if fanning:
        dat["laminar"] = [16./R for R in Re_laminar]
        x = 4
    else:
        dat["laminar"] = [64./R for R in Re_laminar]
        x = 1

    # turbulent
    turb = {}
    for e in eD:
        turb[e] = [F(Rei, e)/x for Rei in Re_turbulent]
        dat["turbulent"] = turb

    # Line to define the fully desarrolled turbulent flux
    dat["fully"] = [(1/(1.14-2*log10(3500/R)))**2/x for R in Re_fully]

    # Save to file
    with open(conf_dir+"moody.dat", "w") as file:
        json.dump(dat, file, indent=4)

class Chart(QtWidgets.QDialog):
    """Generic chart dialog"""

    def __init__(self, parent=None):
        super(Chart, self).__init__(parent)
        self.setWindowTitle(self.title)
        layout = QtWidgets.QGridLayout(self)
        layout.setColumnStretch(3, 1)
        self.plt = mpl(self)
        self.plt.fig.canvas.mpl_connect('button_press_event', self.click)
        layout.addWidget(self.plt, 2, 1, 1, 4)

        btBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Close)
        butonPNG = QtWidgets.QPushButton(QtGui.QIcon(
            os.path.join(IMAGE_PATH, "button", "image.png")),
            QtWidgets.QApplication.translate("pychemqt", "Save as PNG"))
        butonPNG.clicked.connect(self.plt.savePNG)
        butonConfig = QtWidgets.QPushButton(QtGui.QIcon(
            os.path.join(IMAGE_PATH, "button", "configure.png")),
            QtWidgets.QApplication.translate("pychemqt", "Configure"))
        butonConfig.clicked.connect(self.configure)
        butonCalculate = QtWidgets.QPushButton(QtGui.QIcon(
            os.path.join(IMAGE_PATH, "button", "calculator.png")),
            QtWidgets.QApplication.translate("pychemqt", "Calculate point"))
        butonCalculate.clicked.connect(self.calculate)
        btBox.rejected.connect(self.reject)
        btBox.layout().insertWidget(0, butonPNG)
        btBox.layout().insertWidget(0, butonCalculate)
        btBox.layout().insertWidget(0, butonConfig)
        layout.addWidget(btBox, 3, 1, 1, 4)

        self.Preferences = ConfigParser()
        self.Preferences.read(conf_dir+"CheProcessrc")
        self.config()
        self.plot()

        logo = image.imread(os.path.join(IMAGE_PATH, "pychemqt_98.png"))
        self.logo = self.plt.fig.figimage(logo, 0, 0, zorder=1, alpha=0.5)
        self.showMaximized()

    def configure(self):
        dlg = self.configDialog(self.Preferences)
        if dlg.exec_():
            self.Preferences = dlg.value(self.Preferences)
            self.Preferences.write(open(conf_dir+"CheProcessrc", "w"))
            self.plot()

    def config(self):
        """Initialization action in plot don't neccesary to update in plot"""
        pass

    def click(self, event):
        """Define functionality when the mouse click in plot"""
        pass

    def plot(self):
        """Plot procedure"""
        pass

    def calculate(self):
        """Define the functionality when click the calculate point button"""
        pass

    def resizeEvent(self, event):
        """Implement resizeEvent to recalculate the new position of image"""
        self.refixImage()
        QtWidgets.QDialog.resizeEvent(self, event)

    def refixImage(self, event=None):
        """Recalculate image position as resize/move window"""
        xmin, xmax = self.plt.ax.get_xlim()
        ymin, ymax = self.plt.ax.get_ylim()
        x, y = self.plt.ax.transData.transform_point(self.PosLogo)
        hlogo, wlogo = self.logo.get_size()
        if self.PosLogo[0] == 1:
            x -= wlogo
        if self.PosLogo[1] == 1:
            y -= hlogo

        self.logo.ox = x
        self.logo.oy = y

        self.plt.draw()

class Moody(Chart):
    """Moody chart dialog"""
    title = QtWidgets.QApplication.translate("pychemqt", "Moody Diagram")
    configDialog = ConfigDialog
    PosLogo = 5e3, 1.2e-2

    def config(self):
        """Initialization action in plot don't neccesary to update in plot"""

        txt = QtWidgets.QApplication.translate(
            "pychemqt", "Relative roughness") + ", "+r"$r=\frac{\epsilon}{D}$"
        self.plt.fig.text(0.97, 0.5, txt, rotation=90, size='10',
                          va="center", ha="center")
        self.plt.fig.subplots_adjust(
            left=0.1, right=0.9, bottom=0.12, top=0.98)
        self.note = None

    def click(self, event):
        """Update input and graph annotate when mouse click over chart"""
        Re = event.xdata
        f = event.ydata
        ed = None
        method = self.Preferences.getint("Moody", "method")
        fanning = self.Preferences.getboolean("Moody", "fanning")
        F = f_list[method]

        if Re < 2400:
            if fanning:
                f = 16/Re
            else:
                f = 64/Re
        else:
            f_min = F(Re, 0)
            if f < f_min:
                Re = f = 0
            else:
                ed = eD(Re, f)

        self.createCrux(Re, f, ed)

    def _txt(self, Re, f, ed):
        if ed is None:
            txt = "Re: %0.4g\nf: %0.4g" % (Re, f)
        else:
            txt = "Re: %0.4g\ne/D: %0.4g\nf: %0.4g" % (Re, ed, f)
        return txt

    def createCrux(self, Re, f, ed):
        """Create a crux in selected point of plot and show data at bottom
        right corner"""
        if f and Re:
            txt = self._txt(Re, f, ed)

        self.plt.lx.set_ydata(f)
        self.plt.ly.set_xdata(Re)
        if self.note:
            self.note.remove()
            self.note = None
        if f and Re:
            self.note = self.plt.fig.text(0.85, 0.08, txt, size="6", va="top")
        self.plt.draw()

    def plot(self):
        """Plot the Moody chart using the indicate method """
        fanning = self.Preferences.getboolean("Moody", "fanning")
        method = self.Preferences.getint("Moody", "method")

        if fanning:
            x = 4
        else:
            x = 1

        self.plt.ax.set_autoscale_on(False)
        self.plt.ax.clear()

        kw = formatLine(self.Preferences, "Moody", "crux")
        self.plt.lx = self.plt.ax.axhline(**kw)  # the horiz line
        self.plt.ly = self.plt.ax.axvline(**kw)  # the vert line

        xlabel = QtWidgets.QApplication.translate(
            "pychemqt", "Reynolds number") + ", " + r"$Re=\frac{V\rho D}{\mu}$"
        self.plt.ax.set_xlabel(xlabel, ha='center', size='10')
        if fanning:
            ylabel = QtWidgets.QApplication.translate(
                "pychemqt", "Fanning Friction factor")
            formula = r"$f_f=\frac{2hDg}{LV^2}$"
        else:
            ylabel = QtWidgets.QApplication.translate(
                "pychemqt", "Darcy Friction factor")
            formula = r"$f_d=\frac{2hDg}{LV^2}$"
        self.plt.ax.set_ylabel(ylabel+",  " + formula, size='10')
        self.plt.ax.grid(True)
        self.plt.ax.set_xlim(600, 1e8)
        self.plt.ax.set_ylim(0.008/x, 0.11/x)
        self.plt.ax.set_xscale("log")
        self.plt.ax.set_yscale("log")

        xticks = [7e2, 8e2, 9e2, 1e3, 2e3, 3e3, 4e3, 5e3, 6e3, 7e3, 8e3, 9e3,
                  1e4, 2e4, 3e4, 4e4, 5e4, 6e4, 7e4, 8e4, 9e4, 1e5, 2e5, 3e5,
                  4e5, 5e5, 6e5, 7e5, 8e5, 9e5, 1e6, 2e6, 3e6, 4e6, 5e6, 6e6,
                  7e6, 8e6, 9e6, 1e7, 2e7, 3e7, 4e7, 5e7, 6e7, 7e7, 8e7, 9e7]
        self.plt.ax.set_xticks(xticks, minor=False)
        self.plt.ax.set_yticks([], minor=True)

        if fanning:
            yticks = [2e-3, 2.5e-3, 3e-3, 3.5e-3, 4e-3, 5e-3, 6e-3, 7e-3, 8e-3,
                      9e-3, 1e-2, 1.1e-2, 1.2e-2, 1.3e-2, 1.4e-2, 1.5e-2,
                      1.6e-2, 1.7e-2, 1.8e-2, 1.9e-2, 2e-2, 2.1e-2, 2.2e-2,
                      2.3e-2, 2.4e-2, 2.5e-2]
            ytickslabel = [2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, r"$10^{-2}$", "",
                           1.2, "", 1.4, "", 1.6, "", 1.8, "", 2, "", "", "",
                           "", 2.5]
        else:
            yticks = [9e-3, 1e-2, 1.1e-2, 1.2e-2, 1.3e-2, 1.4e-2, 1.5e-2,
                      1.6e-2, 1.7e-2, 1.8e-2, 1.9e-2, 2e-2, 2.1e-2, 2.2e-2,
                      2.3e-2, 2.4e-2, 2.5e-2, 2.6e-2, 2.7e-2, 2.8e-2, 2.9e-2,
                      3e-2, 3.2e-2, 3.4e-2, 3.6e-2, 3.8e-2, 4e-2, 4.2e-2,
                      4.4e-2, 4.6e-2, 4.8e-2, 5e-2, 5.2e-2, 5.4e-2, 5.6e-2,
                      5.8e-2, 6e-2, 6.2e-2, 6.4e-2, 6.6e-2, 6.8e-2, 7e-2,
                      7.5e-2, 8e-2, 8.5e-2, 9e-2, 9.5e-2, 1e-1]
            ytickslabel = [9, r"$10^{-2}$", "", 1.2, "", 1.4, "", 1.6, "", 1.8,
                           "", 2, "", "", "", "", 2.5, "", "", "", "", 3, "",
                           "", "", "", 4, "", "", "", "", 5, "", "", "", "", 6,
                           "", "", "", "", 7, "", 8, "", 9, "", r"$10^{-1}$"]
        self.plt.ax.set_yticks(yticks)
        self.plt.ax.set_yticklabels(ytickslabel)

        if not os.path.isfile(conf_dir+"moody.dat"):
            calculate(self.Preferences)

        load = False
        with open(conf_dir+"moody.dat", "r") as file:
            try:
                dat = json.load(file)
            except ValueError:
                calculate(self.Preferences)
                load = True

            if dat["fanning"] != fanning or dat["method"] != method:
                calculate(self.Preferences)
                load = True

        # Reload file if it's created in last with statement
        if load:
            with open(conf_dir+"moody.dat", "r") as file:
                dat = json.load(file)

        # Plot data
        kw = formatLine(self.Preferences, "Moody", "line")
        self.plt.ax.plot(Re_laminar, dat["laminar"], **kw)
        for ed, f in dat["turbulent"].items():
            self.plt.ax.plot(Re_turbulent, f, **kw)
            title = " " + representacion(ed, tol=4.5)
            if f[-1] > 0.008/x:
                self.plt.ax.text(1e8, f[-1], title, size="x-small",
                                 ha='left', va='center')

        self.plt.ax.plot(Re_fully, dat["fully"], "k", lw=0.5, ls=":")

        # Add explicative legend
        # Laminar zone
        self.plt.ax.add_artist(
            ConnectionPatch((600, 0.01/x), (2400, 0.01/x), "data", "data",
                            arrowstyle="<|-|>", mutation_scale=15, fc="w"))
        txt = QtWidgets.QApplication.translate("pychemqt", "Laminar flux")
        self.plt.ax.text(1200, 0.0095/x, txt, size="small", va="top",
                         ha="center", backgroundcolor="#ffffff")

        # Critic zone
        self.plt.ax.add_artist(
            ConnectionPatch((2400, 0.01/x), (4000, 0.01/x), "data", "data",
                            arrowstyle="<|-|>", mutation_scale=15, fc="w"))
        txt = QtWidgets.QApplication.translate("pychemqt", "Critic\nzone")
        self.plt.ax.text(3200, 0.0095/x, txt, size="small", va="top",
                         ha="center", backgroundcolor="#ffffff")

        # Transition zone
        self.plt.ax.add_artist(
            ConnectionPatch((4000, 0.095/x), (40000, 0.095/x), "data", "data",
                            arrowstyle="<|-|>", mutation_scale=15, fc="w"))
        txt = QtWidgets.QApplication.translate("pychemqt", "Transition Zone")
        self.plt.ax.text(11000, 0.098/x, txt, size="small", va="bottom",
                         ha="center", backgroundcolor="#ffffff")

        # Turbulent zone
        self.plt.ax.add_artist(
            ConnectionPatch((40000, 0.095/x), (9.9e7, 0.095/x), "data", "data",
                            arrowstyle="<|-|>", mutation_scale=15, fc="w"))
        txt = QtWidgets.QApplication.translate(
            "pychemqt", "Turbulent flux fully developed")
        self.plt.ax.text(1e6, 0.098/x, txt, size="small", va="bottom",
                         ha="center", backgroundcolor="#ffffff")

        # Smooth tubes
        self.plt.ax.add_artist(
            ConnectionPatch((1e6, 0.0095/x), (1.5e6, 0.011/x), "data", "data",
                            arrowstyle="<|-|>", mutation_scale=15, fc="w"))
        txt = QtWidgets.QApplication.translate("pychemqt", "Smooth tubes")
        self.plt.ax.text(1e6, 0.009/x, txt, size="small", va="top",
                         ha="center", backgroundcolor="#ffffff")

        # Laminar equation
        if fanning:
            txt = r"$f=\frac{16}{Re}$"
        else:
            txt = r"$f=\frac{64}{Re}$"
        self.plt.ax.text(1.4e3, 0.042/x, txt, size="12",
                         va="top", ha="center", rotation=-66)
        # TODO: Calculate the angle dynamically

        self.plt.draw()

    def calculate(self):
        dlg = CalculateDialog()
        if dlg.exec_():
            Re = dlg.Re.value
            f = dlg.f.value
            eD = dlg.eD.value
            self.createCrux(Re, f, eD)

class CalculateDialog(QtWidgets.QDialog):
    """Dialog to calculate a specified point"""

    def __init__(self, parent=None):
        super(CalculateDialog, self).__init__(parent)
        title = QtWidgets.QApplication.translate(
            "pychemqt", "Calculate friction factor")
        self.setWindowTitle(title)
        layout = QtWidgets.QGridLayout(self)
        label = QtWidgets.QLabel(
            QtWidgets.QApplication.translate("pychemqt", "Method:"))
        layout.addWidget(label, 1, 0)
        self.metodos = QtWidgets.QComboBox()
        for f in f_list:
            line = f.__doc__.split("\n")[1]
            year = line.split(" ")[-1]
            name = line.split(" ")[-3]
            doc = name + " " + year
            self.metodos.addItem(doc)
        self.metodos.currentIndexChanged.connect(self.calculate)
        layout.addWidget(self.metodos, 1, 1, 1, 2)
        self.fanning = QtWidgets.QCheckBox(QtWidgets.QApplication.translate(
            "pychemqt", "Calculate fanning friction factor"))
        self.fanning.toggled.connect(self.calculate)
        layout.addWidget(self.fanning, 2, 0, 1, 3)

        layout.addWidget(QtWidgets.QLabel("Re"), 3, 1)
        self.Re = Entrada_con_unidades(float, tolerancia=4)
        self.Re.valueChanged.connect(self.calculate)
        layout.addWidget(self.Re, 3, 2)
        layout.addWidget(QtWidgets.QLabel("e/D"), 4, 1)
        self.eD = Entrada_con_unidades(float)
        self.eD.valueChanged.connect(self.calculate)
        layout.addWidget(self.eD, 4, 2)
        layout.addWidget(QtWidgets.QLabel("f"), 5, 1)
        self.f = Entrada_con_unidades(float, readOnly=True, decimales=8)
        layout.addWidget(self.f, 5, 2)

        self.buttonBox = QtWidgets.QDialogButtonBox(
            QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Close)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)
        layout.addWidget(self.buttonBox, 10, 1, 1, 2)

    def calculate(self, value):
        index = self.metodos.currentIndex()
        F = f_list[index]
        Re = self.Re.value
        eD = self.eD.value
        if Re and eD is not None:
            f = F(Re, eD)
            if self.fanning.isChecked():
                f /= 4
            self.f.setValue(f)

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = Moody()
    Dialog.show()
    sys.exit(app.exec_())


import tornado.httpserver
import tornado.ioloop
import tornado.web
from pymongo import MongoClient

from lib import game
import websocket

import os

class Application(tornado.web.Application):
	def __init__(self, newGame):
		self.game = newGame

		urls = [
			(r'/', websocket.WSHandler, {'game': self.game})
		]

		settings = dict(
			template_path=os.path.join(os.path.dirname(__file__), 'templates'),
			static_path=os.path.join(os.path.dirname(__file__), 'static'),
			cookie_secret='__FIX ME:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__',
			debug=True
		)
		super(Application, self).__init__(urls, **settings)

def main():
	newGame = game.Game()

	http_server = tornado.httpserver.HTTPServer(Application(newGame))
	http_server.listen(4000)
	tornado.ioloop.IOLoop.current().start()

if __name__ == '__main__':
	main()


### Imports ###
import sys, queue, threading, requests, datetime
from colorama import Fore,init

### Variables ###
init()
input_queue = queue.Queue()
result_queue = queue.Queue()
thread_lock = threading.Lock()
date_time = datetime.datetime.now()
current_time = date_time.time()

INFO = "[\x1b[33m?\x1b[37m] "
ERROR = "[\x1b[31m-\x1b[37m] "
SUCCESS = "[\x1b[32m+\x1b[37m] "

### Editable Variables ###

timeout_period = 1

class ProcessThread(threading.Thread):
    def __init__(self, in_queue, out_queue):
        threading.Thread.__init__(self)
        self.in_queue = in_queue
        self.out_queue = out_queue

    def run(self):
        while True:
            result = self.process(self.in_queue.get())
            if (result is not None):
                self.out_queue.put(result)

            self.in_queue.task_done()

    def process(self, proxy):
        clean_proxy = proxy.replace("\n", "")
        try:
            proxy_formatter = {
                "http": "http://" + clean_proxy,
                "https": "http://" + clean_proxy
            }
            r = requests.get("http://ipinfo.io/json", proxies=proxy_formatter, timeout=timeout_period)
            printableOutput = (Fore.GREEN + '[%s:%s:%s]  %s' % (current_time.hour, current_time.minute, current_time.second , r.json()["ip"]))
            with thread_lock:
                print(printableOutput)

                return "%s" % (proxy)
        except:
            with thread_lock:
                print(Fore.RED + '[%s:%s:%s]  %s' % (current_time.hour, current_time.minute, current_time.second , clean_proxy))
            return None

    def terminate(self):
        None

class LogWorking(threading.Thread):
	def __init__(self, queue, output_file):
		threading.Thread.__init__(self)
		self.queue = queue
		self.output = open(output_file, "a")
		self.shutdown = False

	def log(self, string):
		print(string, file=self.output)

	def run(self):
		while not self.shutdown:
			self.log(self.queue.get())
			self.queue.task_done()

	def terminate(self):
		self.output.close()
		self.shutdown = True

def main():
	# Check Argument Length
	if (len(sys.argv) < 4):
		print("%s Incorrect usage!" % (ERROR))
		print("%s Usage: %s <proxy list> <threads> <output file>" % (INFO, sys.argv[0]))
		exit(1)

	try:
		ip_list = [line.rstrip("\n") for line in open(sys.argv[1], "r")]
	except BaseException as error:
		print(str(error))
		exit(1)

	# Check If File Is Empty
	if (len(ip_list) == 0):
		print("%s Chosen file is blank" % (ERROR))
		exit(1)

	# Load Input Queue
	i = 0
	for ip in ip_list:
		input_queue.put(ip)
		i += 1
		sys.stdout.write("\rAdded %d proxies to queue" % (i))
		sys.stdout.flush()

	print("\n\n%s Checking %d proxies" % (INFO, len(ip_list)))

	# Start Workers
	workers = []
	for i in range(0, int(sys.argv[2])):
		thread = ProcessThread(input_queue, result_queue)
		thread.daemon = True
		thread.start()
		workers.append(thread)

	logger = LogWorking(result_queue, sys.argv[3])
	logger.daemon = True
	logger.start()

	# Wait until our queues are finished
	input_queue.join()
	result_queue.join()
	logger.terminate()
	for worker in workers:
		worker.terminate()

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


import tkinter as tk
from tkinter import ttk
import sqlite3
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from collections import defaultdict

class GraphiquePreuves(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        self.controller = controller

        self.bouton_afficher_graphique = ttk.Button(self, text="Afficher le graphique", command=self.afficher_graphique)
        self.bouton_afficher_graphique.pack(pady=10)

        self.graphique_frame = ttk.Frame(self)
        self.graphique_frame.pack(pady=10)

    def afficher_graphique(self):
        # Connexion à la base de données
        try:
            connexion = sqlite3.connect('database.db')
            curseur = connexion.cursor()

            # Exemple de requête SQL, ajustez-la en fonction de votre structure de base de données
            curseur.execute('SELECT enquId, type FROM Preuves')
            resultats = curseur.fetchall()

            # Fermez la connexion après avoir récupéré les données
            connexion.close()

            # Traitement des données et création du graphique
            data_dict = defaultdict(lambda: defaultdict(int))

            for resultat in resultats:
                enquId, type_preuve = resultat
                data_dict[enquId][type_preuve] += 1

            # Création du graphique à barres empilées
            figure = Figure(figsize=(8, 6), dpi=100)
            subplot = figure.add_subplot(111)

            enquIds = list(data_dict.keys())
            types = list(set(type_preuve for type_preuve in data_dict[enquIds[0]].keys()))  # Prend tous les types de preuves

            bottom = [0] * len(types)

            for enquId in enquIds:
                valeurs = [data_dict[enquId][type_preuve] for type_preuve in types]
                subplot.bar(types, valeurs, bottom=bottom, label=f"enquId {enquId}")
                bottom = [b + v for b, v in zip(bottom, valeurs)]

            subplot.set_xlabel('Type de Preuve')
            subplot.set_ylabel('Nombre de Preuves')
            subplot.legend()

            max_y = max(bottom)
            subplot.set_yticks(range(max_y + 1))

            canvas = FigureCanvasTkAgg(figure, master=self.graphique_frame)
            canvas.draw()
            canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)

        except sqlite3.Error as e:
            print(f"Erreur lors de la récupération des données depuis la base de données : {e}")

# Exemple d'utilisation de la classe dans l'application principale
class Application(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.title("Graphique des Preuves par Type")
        self.geometry("800x600")

        self.graphique_preuves = GraphiquePreuves(self, self)
        self.graphique_preuves.pack()

# Lancement de l'application
app = Application()
app.mainloop()


import collections
import datetime
import itertools
import math
import os

import numpy as np
import torch

from .abstract_game import AbstractGame

class MuZeroConfig:
    def __init__(self):
        # 这里有更多信息: https://github.com/werner-duvaud/muzero-general/wiki/Hyperparameter-Optimization

        self.seed = 0  # numpy、torch和游戏的种子
        self.max_num_gpus = None  # 确定要使用的最大GPU数。如果有足够的显存，使用单个GPU（将其设置为1）通常会更快。None会使用所有可用的GPU

        ### 游戏
        self.observation_shape = (3, 11, 11)  # 游戏观察的尺寸必须为3（通道、高度、宽度）。对于1D数组，请将其形状改为（1，1，数组长度）
        self.action_space = list(range(11 * 11))  # 所有可能动作的固定列表。您应该只编辑长度
        self.players = list(range(2))  # 玩家的列表。您应该只编辑长度
        self.stacked_observations = 0  # 要添加到 当前观察 的 先前观察 和 先前动作 的数量

        # 评估
        self.muzero_player = 0  # Muzero 玩游戏的先后手（0:Muzero 先手，1:Muzero 后手）
        self.opponent = "random"  # MuZero 对战的硬编码智能体，以评估他在多人游戏中的进展。它不影响训练。如果在游戏类中实现，分为 None, "random" or "expert"

        ### 自博弈
        self.num_workers = 1  # 给回放池提供数据的并发自博弈 工作进程/线程 数目
        self.selfplay_on_gpu = False
        self.max_moves = 121  # 如果游戏未在之前完成，则能移动的最大数量
        self.num_simulations = 300  # 自模拟的未来移动次数（MCTS对当前根结点展开模拟的次数）
        self.discount = 1  # 按时间顺序排列的奖励折扣
        self.temperature_threshold = None  # 将 visit_softmax_temperature_fn 给出的温度降至0（即选择最佳动作）之前的移动次数。如果是 None，visit_softmax_temperature_fn 每次都会被用到

        # 根先验探索噪声
        self.root_dirichlet_alpha = 0.3  # 狄利克雷分布的α参数
        self.root_exploration_fraction = 0.25  # 噪声所占的比例

        # UCB 公式
        self.pb_c_base = 19652
        self.pb_c_init = 1.25

        ### 神经网络
        self.network = "resnet"  # "resnet" 或 "fullyconnected"
        self.support_size = 10  # 价值和奖励被缩放（几乎都是用sqrt）并编码在一个向量上，向量的范围为-support_size到support_size。选择它以便使 support_size <= sqrt(max(abs(discounted reward)))

        # 残差网络
        self.downsample = False  # 表示网络 前的下采样观测值, False / "CNN" (更轻量级的) / "resnet" (见论文附录网络架构)
        self.blocks = 3  # ResNet中的块数
        self.channels = 64  # ResNet中的通道数
        self.reduced_channels_reward = 2  # 奖励头 中的通道数
        self.reduced_channels_value = 2  # 价值头 中的通道数
        self.reduced_channels_policy = 4  # 策略头 中的通道数
        self.resnet_fc_reward_layers = [32]  # 在 动态网络 的 奖励头 中定义隐藏层
        self.resnet_fc_value_layers = [32]  # 在 预测网络 的 价值头 中定义隐藏层
        self.resnet_fc_policy_layers = [32]  # 在 预测网络 的 策略头 中定义隐藏层

        # 全连接神经网络
        self.encoding_size = 32
        self.fc_representation_layers = []  # 定义 表示网络 中的隐藏层
        self.fc_dynamics_layers = [64]  # 定义 动态网络 中的隐藏层
        self.fc_reward_layers = [64]  # 定义 奖励网络 中的隐藏层
        self.fc_value_layers = []  # 定义 价值网络 中的隐藏层
        self.fc_policy_layers = []  # 定义 策略网络 中的隐藏层

        ### 训练
        self.results_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../results", os.path.basename(__file__)[:-3], datetime.datetime.now().strftime("%Y-%m-%d--%H-%M-%S"))  # 存储 模型权重 和 Tensorboard 日志的路径
        self.save_model = True  # 将 results_path 中的检查点另存为 model.checkpoint
        self.training_steps = 2000  # 训练步总数（即根据批次更新权重）
        self.batch_size = 64  # 在每个训练步中 训练的游戏片段 的数量
        self.checkpoint_interval = 5  # 保存模型的训练步间隔
        self.value_loss_weight = 1  # 缩放价值损失以避免价值函数的过拟合，论文建议为0.25（见论文附录 重新分析）
        self.train_on_gpu = torch.cuda.is_available()  # 在GPU上训练（如果可用）

        self.optimizer = "Adam"  # "Adam" or "SGD". 论文中使用 SGD
        self.weight_decay = 1e-4  # L2权重正则化
        self.momentum = 0.9  # 仅当优化器为SGD时使用

        # 指数学习速率调度器
        self.lr_init = 0.002  # 初始学习率
        self.lr_decay_rate = 0.9  # 将其设置为1以使用恒定的学习速率
        self.lr_decay_steps = self.training_steps

        ### 回放池
        self.replay_buffer_size = 10000  # 要保留在回放池中的自博弈游戏盘数
        self.num_unroll_steps = 121  # 每盘游戏为批元素保留的游戏移动数（移动为样本的单位），即论文中的“展开的K假设步”
        self.td_steps = 121  # 计算 目标价值 时要考虑的未来步数，即论文中的“n-step前瞻的n”
        self.PER = True  # 优先回放（见论文附录 训练），优先选择回放池中网络意外的元素
        self.PER_alpha = 0.5  # 使用多少优先级，0对应于uniform分布的情况，论文建议1

        # 重新分析（见论文附录 重新分析）
        self.use_last_model_value = False  # 使用最后一个模型提供更新鲜、稳定的 n-step 价值（见论文附录 重新分析）
        self.reanalyse_on_gpu = False

        ### 调整 自博弈/训练 比率，以避免 过拟合/欠拟合
        self.self_play_delay = 0  # 每次玩一盘游戏后等待的秒数
        self.training_delay = 0  # 每个训练步后等待的秒数
        self.ratio = 1 / 50  # 每个 自博弈步 的 期望训练步 比率。与同步版本等效，训练可能需要更长的时间。设置为“None”以禁用它

    def visit_softmax_temperature_fn(self, trained_steps):
        """
        更改 访问次数分布 的参数——确保随着训练的进行，动作选择变得更加贪婪。越小，越有可能选择最佳行动（即访问次数最多）。

        Returns:
            Positive float.
        """
        if trained_steps < 0.5 * self.training_steps:
            return 1.0
        elif trained_steps < 0.75 * self.training_steps:
            return 0.5
        else:
            return 0.25

class Game(AbstractGame):
    """
    游戏装饰器
    """

    def __init__(self, seed=None):
        self.env = Hex()

    def step(self, action):
        """
        在游戏中执行一个动作

        Args:
            action : 要采取的 动作空间 中的 动作。

        Returns:
            新的观察、奖励和（标记游戏是否结束）布尔值。
        """
        observation, reward, done = self.env.step(action)
        return observation, reward, done

    def to_play(self):
        """
        返回当前的玩家

        Returns:
            当前玩家，它应该是配置中玩家列表的一个元素
        """
        return self.env.to_play()

    def legal_actions(self):
        """
        应在每个回合返回合法动作，如果不可用，可返回整个动作空间。在每个回合，游戏必须能够处理一个返回的动作。
        对于计算合法动作太长的复杂游戏，其想法是将合法动作定义为整个动作空间，但如果动作非法，则返回负奖励。

        Returns:
            An array of integers，动作空间的子集
        """
        return self.env.legal_actions()

    def reset(self):
        """
        为新游戏重置游戏

        Returns:
            游戏的初始化观察
        """
        return self.env.reset()

    def close(self):
        """
        正确地结束游戏
        """
        pass

    def render(self):
        """
        可视化（渲染）游戏观察
        """
        self.env.render()
        # input("Press enter to take a step ")

    def human_to_action(self):
        """
        对于多人游戏，要求用户采取合法动作并返回相应的动作编号

        Returns:
            An integer from the action space.
        """
        valid = False
        while not valid:
            valid, action = self.env.human_input_to_action()
        return action

    def action_to_string(self, action):
        """
        将动作编号转换为表示该动作的字符串
        Args:
            action_number: an integer from the action space.
        Returns:
            表示该动作的 字符串
        """
        return self.env.action_to_human_input(action)

class Hex:
    def __init__(self):
        self.board_size = 11
        self.board = np.zeros((self.board_size, self.board_size), dtype="int32")
        self.player = 1  # 红棋为1，蓝棋为-1
        self._directions = [(-1, 0), (0, -1), (1, -1), (1, 0), (0, 1), (-1, 1)]
        self.column_markers = [
            chr(x) for x in range(ord("A"), ord("A") + self.board_size)
        ]
        self.row_markers = [
            str(x) for x in range(1, self.board_size + 1)
        ]

    def to_play(self):
        return 0 if self.player == 1 else 1  # 先手返回0，后手返回1

    def reset(self):
        self.board = np.zeros((self.board_size, self.board_size), dtype="int32")
        self.player = 1
        return self.get_observation()

    def step(self, action):
        x = math.floor(action / self.board_size)
        y = action % self.board_size
        self.board[x][y] = self.player

        done = self.is_finished()

        reward = 1 if done else 0  # 当前玩家获胜，奖励为1   R(St)对应Player(St-1)

        self.player *= -1

        return self.get_observation(), reward, done

    def get_observation(self):
        board_player1 = np.where(self.board == 1, 1.0, 0.0)
        board_player2 = np.where(self.board == -1, 1.0, 0.0)
        board_to_play = np.full((11, 11), self.player, dtype="int32")
        return np.array([board_player1, board_player2, board_to_play])  # 3, 11, 11

    def legal_actions(self):
        legal = []
        for i in range(self.board_size):
            for j in range(self.board_size):
                if self.board[i][j] == 0:
                    legal.append(i * self.board_size + j)
        return legal

    def is_finished(self):
        for j in range(self.board_size):
            if self.is_connected((0, j), 1):
                return True
        for i in range(self.board_size):
            if self.is_connected((i, 0), -1):
                return True
        return False  # 游戏未结束

    def is_connected(self, root, color):
        """判断从上到下或者从左到右是否形成完整的连接，若是则返回True，否则返回False"""
        if self.board[root] != color:
            return False
        visited, queue = {root}, collections.deque([root])
        while queue:
            pos = queue.popleft()
            for neighbor in self.get_neighbors(pos, color):
                if neighbor not in visited:
                    if (color == 1 and neighbor[0] == self.board_size - 1) or (
                            color == -1 and neighbor[1] == self.board_size - 1):
                        return True
                    visited.add(neighbor)
                    queue.append(neighbor)
        return False

    def get_neighbors(self, pos, color):
        """返回一个包含所有同颜色邻居的列表"""
        x, y = pos
        neighbors = []
        for x_offset, y_offset in self._directions:
            nx, ny = (x + x_offset, y + y_offset)
            if self.is_valid_pos(nx, ny):
                if self.board[(nx, ny)] == color:
                    neighbors.append((nx, ny))
        return neighbors

    def is_valid_pos(self, i, j):
        if i < 0 or j < 0 or i >= self.board_size or j >= self.board_size:
            return False
        return True

    def render(self):
        pretty_print_map = {
            1: '\x1b[0;36;41mR  ',
            0: '\x1b[0;31;43m-  ',
            -1: '\x1b[0;31;46mB  ',
        }
        board = np.copy(self.board)
        # 原始棋盘内容
        raw_board_contents = []
        for i in range(self.board_size):
            row = []
            for j in range(self.board_size):
                row.append(pretty_print_map[board[i, j]])
                row.append('\x1b[0m')
            raw_board_contents.append(''.join(row))
        # 行标签 N~1
        row_labels_left = [" " * (self.board_size - i) + '%2d' % i + "\\" for i in
                           range(self.board_size, 0, -1)]
        row_labels_right = ["\\ " + '%2d' % i for i in range(self.board_size, 0, -1)]
        # 带标注的每一行的内容
        annotated_board_contents = [''.join(r) for r in zip(row_labels_left, raw_board_contents, row_labels_right)]
        # 列标签
        header_footer_rows = ['   ' + '  '.join('ABCDEFGHIJK'[:self.board_size]) + '   ']
        tailer_footer_rows = ["   " + " " * (self.board_size) + '  '.join(
            'ABCDEFGHIJK'[:self.board_size]) + '   ']
        # 带标注的棋盘
        # itertools.chain将不同容器中的元素连接起来，便于遍历
        annotated_board = '\n'.join(itertools.chain(header_footer_rows, annotated_board_contents, tailer_footer_rows))
        print(annotated_board)

    def human_input_to_action(self):
        human_input = input("Enter an action: ")
        if (
            len(human_input) == 2
            and human_input[0] in self.column_markers
            and human_input[1:] in self.row_markers
        ):
            y = ord(human_input[0]) - 65
            x = self.board_size - int(human_input[1:])
            if self.board[x][y] == 0:
                return True, x * self.board_size + y
        return False, -1

    def action_to_human_input(self, action):
        x = math.floor(action / self.board_size)
        y = action % self.board_size
        x = str(self.board_size - x)
        y = chr(y + 65)
        return y + x


from abc import ABC, abstractmethod
from typing import Tuple

import torch
from torch import Tensor

class NearestNeighbors(ABC):
    r"""
    An abstract class to define a nearest neighbors data structure. Classes
    implementing this interface are intended for computing proponents / opponents in
    certain implementations of `TracInCPBase`. In particular, it is for use in
    implementations which compute proponents / opponents of a test instance by
    1) storing representations of training instances within a nearest neighbors data
    structure, and 2) finding within that structure the nearest neighbor of the
    representation of a test instance. The assumption is that the data structure
    stores the tensors passed to the `setup` method, which we refer to as the "stored
    tensors". If this class is used to find proponents / opponents, the nearest
    neighbors of a tensor should be the stored tensors that have the largest
    dot-product with the query.
    """

    @abstractmethod
    def get_nearest_neighbors(
        self, query: torch.Tensor, k: int
    ) -> Tuple[Tensor, Tensor]:
        r"""
        Given a `query`, a tensor of shape (N, *), returns the nearest neighbors in the
        "stored tensors" (see above). `query` represents a batch of N tensors, each
        of common but arbitrary shape *. We always assume the 0-th dimension indexes
        the batch. In use cases of this class for computing proponents / opponents,
        the nearest neighbors of a tensor should be the stored tensors with the largest
        dot-product with the tensor, and the tensors in `query` will all be 1D,
        so that `query` is 2D.

        Args:
            query (Tensor): tensor representing the batch of tensors for which k-nearest
                    neighbors are desired. `query` is of shape (N, *), where N is the
                    size of the batch, i.e. the 0-th dimension of `query` indexes the
                    batch. * denotes an arbitrary shape, so that each tensor in the
                    batch can be of a common, but arbitrary shape.
            k (int): The number of nearest neighbors to return.

        Returns:
            results (tuple): A tuple of `(indices, distances)` is returned. `indices`
                    is a 2D tensor where `indices[i,j]` is the index (within the
                    "stored tensors" passed to the `setup` method) of the `j`-th
                    nearest neighbor of the `i`-th instance in query, and
                    `distances[i,j]` is the corresponding distance. `indices` should
                    be of dtype `torch.long` so that it can be used to index torch
                    tensors.
        """
        pass

    @abstractmethod
    def setup(self, data: torch.Tensor) -> None:
        r"""
        `data` denotes the "stored tensors". These are the tensors within which we
        want to find the nearest neighbors to each tensor in a batch of tensors, via a
        call to the`get_nearest_neighbors` method. Before we can call it, however,
        we need to first store the stored tensors, by doing processing that indexes
        the stored tensors in a form that enables nearest-neighbors computation.
        This method does that preprocessing, and is assumed to be called before any
        call to `get_nearest_neighbors`. For example, this method might put the
        stored tensors in a K-d tree. The tensors in the "stored tensors" can be of a
        common, but arbitrary shape, denoted *, so that `data` is of shape (N, *),
        where N is the number of tensors in the stored tensors. Therefore, the 0-th
        dimension indexes the tensors in the stored tensors.

        Args:
            data (Tensor): A tensor of shape (N, *) representing the stored tensors.
                    The 0-th dimension indexes the tensors in the stored tensors,
                    so that `data[i]` is the tensor with index `i`. The nearest
                    neighbors of a query will be referred to by their index.
        """
        pass

class AnnoyNearestNeighbors(NearestNeighbors):
    """
    This is an implementation of `NearestNeighbors` that uses the Annoy module. At a
    high level, Annoy finds nearest neighbors by constructing binary trees in which
    vectors reside at leaf nodes. Vectors near each other will tend to be in the same
    leaf node. See https://tinyurl.com/2p89sb2h and https://github.com/spotify/annoy
    for more details. Annoy has 1 key parameter: the number of trees to construct.
    Increasing the number of trees leads to more accurate results, but longer time to
    create the trees and memory usage. As mentioned in the `NearestNeighbors`
    documentation, for the use case of computing proponents / opponents, the nearest
    neighbors returned should be those with the largest dot product with the query
    vector. The term "vector" is used here because Annoy stores 1D vectors. However
    in our wrapper around Annoy, we will allow the stored tensors to be of a common
    but arbitrary shape *, and flatten them before storing in the Annoy data structure.
    """

    def __init__(self, num_trees: int = 10) -> None:
        """
        Args:
            num_trees (int): The number of trees to use. Increasing this number gives
                    more accurate computation of nearest neighbors, but requires longer
                    setup time to create the trees, as well as memory.
        """
        try:
            import annoy  # noqa
        except ImportError:
            raise ValueError(
                (
                    "Using `AnnoyNearestNeighbors` requires installing the annoy "
                    "module. If pip is installed, this can be done with "
                    "`pip install --user annoy`."
                )
            )

        self.num_trees = num_trees

    def setup(self, data: torch.Tensor) -> None:
        """
        `data` denotes the "stored tensors". These are the tensors within which we
        want to find the nearest neighbors to a query tensor, via a call to the
        `get_nearest_neighbors` method. Before we can call `get_nearest_neighbors`,
        we need to first store the stored tensors, by doing processing that indexes
        the stored tensors in a form that enables nearest-neighbors computation.
        This method does that preprocessing, and is assumed to be called before any
        call to `get_nearest_neighbors`. In particular, it creates the trees used to
        index the stored tensors. This index is built to enable computation of
        vectors that have the largest dot-product with the query tensors. The tensors
        in the "stored tensors" can be of a common, but arbitrary shape, denoted *, so
        that `data` is of shape (N, *), where N is the number of tensors in the stored
        tensors. Therefore, the 0-th dimension indexes the tensors in the stored
        tensors.

        Args:
            data (Tensor): A tensor of shape (N, *) representing the stored tensors.
                    The 0-th dimension indexes the tensors in the stored tensors,
                    so that `data[i]` is the tensor with index `i`. The nearest
                    neighbors of a query will be referred to by their index.
        """
        import annoy

        data = data.view((len(data), -1))
        projection_dim = data.shape[1]
        self.knn_index = annoy.AnnoyIndex(projection_dim, "dot")
        for (i, projection) in enumerate(data):
            self.knn_index.add_item(i, projection)
        self.knn_index.build(self.num_trees)

    def get_nearest_neighbors(
        self, query: torch.Tensor, k: int
    ) -> Tuple[Tensor, Tensor]:
        r"""
        Given a `query`, a tensor of shape (N, *), returns the nearest neighbors in the
        "stored tensors" (see above). `query` represents a batch of N tensors, each
        of common but arbitrary shape *. We always assume the 0-th dimension indexes
        the batch. In use cases of this class for computing proponents / opponents,
        the nearest neighbors of a tensor should be the stored tensors with the largest
        dot-product with the tensor, and the tensors in `query` will all be 1D,
        so that `query` is 2D. This implementation returns the stored tensors
        that have the largest dot-product with the query tensor, and does not constrain
        the tensors in `query` or in the stored tensors to be 1D. If tensors are of
        dimension greater than 1D, their dot-product will be defined to be the
        dot-product of the flattened version of tensors.

        Args:
            query (Tensor): tensor representing the batch of tensors for which k-nearest
                    neighbors are desired. `query` is of shape (N, *), where N is the
                    size of the batch, i.e. the 0-th dimension of `query` indexes the
                    batch. * denotes an arbitrary shape, so that each tensor in the
                    batch can be of a common, but arbitrary shape.
            k (int): The number of nearest neighbors to return.

        Returns:
            results (tuple): A tuple of `(indices, distances)` is returned. `indices`
                    is a 2D tensor where `indices[i,j]` is the index (within the
                    "stored tensors" passed to the `setup` method) of the `j`-th
                    nearest neighbor of the `i`-th instance in query, and
                    `distances[i,j]` is the corresponding distance. `indices` should
                    be of dtype `torch.long` so that it can be used to index torch
                    tensors.
        """
        query = query.view((len(query), -1))
        indices_and_distances = [
            self.knn_index.get_nns_by_vector(instance, k, include_distances=True)
            for instance in query
        ]
        indices, distances = zip(*indices_and_distances)
        indices = torch.Tensor(indices).type(torch.long)
        distances = torch.Tensor(distances)
        return indices, distances


import os
from typing import Any, Dict

from airflow.operators.python_operator import PythonOperator
from airflow.utils.decorators import apply_defaults
try:
    from cloud_function_utils import make_iap_request, IAP_CLIENT_ID
except ImportError:
    from recidiviz.cloud_functions.cloud_function_utils import make_iap_request, IAP_CLIENT_ID

def make_iap_export_request(url: str) -> Dict[str, Any]:
    client_id = IAP_CLIENT_ID[os.environ.get('GCP_PROJECT_ID')]
    # make_iap_request raises an exception if the returned status code is not 200
    response = make_iap_request(url, client_id)

    # When operators return a value in airflow, the result is put into xcom for other operators to access it.
    # However, the result must be a built in Python data type otherwise the operator will not return successfully.
    return {
        'status_code': response.status_code,
        'text': response.text
    }

class IAPHTTPRequestOperator(PythonOperator):
    @apply_defaults
    def __init__(
            self,
            task_id: str,
            url: str,
            *args, **kwargs) -> None:
        super().__init__(task_id=task_id,
                         python_callable=make_iap_export_request,
                         op_kwargs={'url': url},
                         *args, **kwargs)


import pygame
from pygame.sprite import Sprite

class SubZero(Sprite):

    def __init__(self, screen, settings):

        super().__init__()

        self.screen = screen
        self.screen_rect = self.screen.get_rect()
        self.settings = settings

        self.image = pygame.image.load("imagenes/subzero_derecha.png")
        self.rect = self.image.get_rect()

        self.rect.y = self.screen_rect.height - self.rect.height
        self.rect.x = self.screen_rect.width / 2 - self.rect.width / 2

        self.mov_right = False
        self.mov_left = False

    def update(self):

        if self.mov_right:
            self.rect.x += 1

        elif self.mov_left:
            self.rect.x -= 1

    def blitme(self):
        self.screen.blit(self.image, self.rect)


from flask import Blueprint, url_for, redirect, current_app
from flask_login import LoginManager, login_required, logout_user, current_user

logout = Blueprint('logout', __name__)
login_manager = LoginManager()
login_manager.init_app(logout)

@logout.route('/logout')
@login_required
def show():
    current_app.logger.info(f"Logout user with id {current_user.id}")
    logout_user()
    return redirect(url_for('login.show') + '?success=logged-out')


import result
import csv

data = {}
RESULT = result.BRACKET_ORIG

for year in RESULT:
	count = 1
	data[year] = []
	for team in RESULT[year]:
		data[year].append([team, count])
		count += 1

for year in data:
    with open("./our_data/lookup/" + str(year) + "_lookup.csv", "w") as outfile:

        writer = csv.writer(outfile, delimiter=',', lineterminator='\n')

        writer.writerows(data[year])


"""Class definition of the In-Memory Landscape Model store."""
import base
import numpy
import typing

class InMemoryStore(base.Store):
    """
    A Landscape model store that manages data exchange entirely by Python objects in memory.

    PARAMETERS
    None.
    """
    # CHANGELOG
    base.VERSION.added("1.1.1", "`store.InMemoryStore` ")
    base.VERSION.changed("1.3.27", "`store.InMemoryStore` `slice` keyword renamed to `slices`")
    base.VERSION.changed("1.3.27", "`store.InMemoryStore` updated")
    base.VERSION.changed("1.3.33", "`store.InMemoryStore` stores physical unit if specified")
    base.VERSION.added("1.4.1", "Changelog in `store.InMemoryStore` ")
    base.VERSION.changed("1.4.1", "`store.InMemoryStore` class documentation")
    base.VERSION.changed("1.4.9", "`store.InMemoryStore` data type access")
    base.VERSION.changed("1.5.3", "`store.InMemoryStore` changelog uses markdown for code elements")
    base.VERSION.added("1.7.0", "Type hints to `stores.InMemoryStore` ")
    base.VERSION.changed("1.8.0", "Replaced Legacy format strings by f-strings in `stores.InMemoryStore` ")
    base.VERSION.changed("1.9.0", "Switched to Google docstring style in `stores.InMemoryStore` ")

    def __init__(self) -> None:
        """Initializes an InMemoryStore."""
        self._data = {}
        self._scales = {}
        self._unit = {}

    def describe(self, name: str) -> dict[str, typing.Any]:
        """
        Describes a dataset in the store.

        Args:
            name: The name of the dataset.

        Returns:
            A dictionary describing the dataset.
        """
        return {"scales": self._scales[name], "unit": self._unit[name]}

    def get_values(self, name: str, **keywords) -> typing.Any:
        """
        Gets the values of a data set from the store.

        Args:
            name: The name of the data set.
            keywords: Additional keywords.

        Returns:
            The values of the data set in their original representation.
        """
        try:
            values = self._data[name]
        except KeyError:
            raise KeyError(f"InMemoryStore does not contain data for '{name}'")
        return values

    def set_values(
            self,
            name: str,
            values: typing.Any,
            scales: typing.Optional[str] = None,
            unit: typing.Optional[str] = None,
            shape: typing.Optional[typing.Sequence[int]] = None,
            data_type: typing.Optional[type] = None,
            chunks: typing.Optional[typing.Sequence[slice]] = None,
            create: bool = True,
            slices: typing.Optional[typing.Sequence[slice]] = None
    ) -> None:
        """
        Stores a data set in the store.

        Args:

            name: The name of the data set.
            values: The values of the data set.
            scales: The scales to which the values of the data set apply.
            unit: The physical unit of the values.
            shape: The shape of a newly created empty array.
            data_type: The datatype of a newly created empty array.
            chunks: The chunk size for a newly created empty array.
            create: Specifies whether a data set should be created or not.
            slices: Defines the portion of the data set that was passed to the function.

        Returns:
            Nothing.
        """
        if isinstance(values, type):
            type_name = f"{values.__module__}.{values.__qualname__}"
            # noinspection SpellCheckingInspection
            if type_name == "numpy.ndarray" and create:
                self._data[name] = numpy.zeros(shape, data_type)
            else:
                raise TypeError(f"Unsupported type: {type(values)}")
        elif isinstance(values, numpy.ndarray) and slices is not None:
            self._data[name][slices] = values
        else:
            self._data[name] = values
        self._scales[name] = scales
        self._unit[name] = unit

    def has_dataset(self, name: str, partial: bool = False) -> bool:
        """
        Checks whether a dataset exists in the store or not.

        Args:
            name: The name of the dataset.
            partial: Specifies whether to also check partial dataset paths or not.

        Returns:
            A boolean value indicating whether the dataset exists or not.
        """
        return name in self._data