"""
A Python module that computes the protein interaction graph from a PDB file.

Author: Eric J. Ma
License: MIT

Intended usage:

```python
from proteingraph import read_pdb

G = read_pdb("/path/to/file.pdb")
```
"""
from collections import defaultdict
from functools import partial
from itertools import combinations
from pathlib import Path

import networkx as nx
import numpy as np
import pandas as pd
from biopandas.pdb import PandasPdb
from scipy.spatial import Delaunay
from scipy.spatial.distance import euclidean, pdist, rogerstanimoto, squareform
from sklearn.preprocessing import LabelBinarizer

from .resi_atoms import (
    AA_RING_ATOMS,
    AROMATIC_RESIS,
    BACKBONE_ATOMS,
    BOND_TYPES,
    CATION_PI_RESIS,
    CATION_RESIS,
    DISULFIDE_ATOMS,
    DISULFIDE_RESIS,
    HYDROPHOBIC_RESIS,
    IONIC_RESIS,
    ISOELECTRIC_POINTS_STD,
    MOLECULAR_WEIGHTS_STD,
    NEG_AA,
    PI_RESIS,
    POS_AA,
    RESI_NAMES,
)

def pdb2df(path: Path) -> nx.Graph:
    """
    Parse the PDB file as a pandas DataFrame object.

    Backbone chain atoms are ignored for the calculation
    of interacting residues.
    """
    atomic_df = PandasPdb().read_pdb(str(path)).df["ATOM"]
    atomic_df["node_id"] = (
        atomic_df["chain_id"]
        + atomic_df["residue_number"].map(str)
        + atomic_df["residue_name"]
    )
    return atomic_df

def compute_chain_pos_aa_mapping(pdb_df):
    """Compute the mapping: chain -> position -> aa."""
    chain_pos_aa = defaultdict(dict)
    for (chain, pos, aa), _ in pdb_df.groupby(
        ["chain_id", "residue_number", "residue_name"]
    ):
        chain_pos_aa[chain][pos] = aa
    return chain_pos_aa

def read_pdb(path: Path) -> nx.Graph:
    """
    Parse PDB file into protein graph.

    Overall function to read PDB and get back graph.
    """
    pdb_df = pdb2df(path)
    rgroup_df = compute_rgroup_dataframe(pdb_df)
    chain_pos_aa = compute_chain_pos_aa_mapping(pdb_df)

    edge_funcs = [
        partial(add_hydrophobic_interactions, rgroup_df=rgroup_df),
        partial(add_disulfide_interactions, rgroup_df=rgroup_df),
        partial(add_hydrogen_bond_interactions, rgroup_df=rgroup_df),
        partial(add_ionic_interactions, rgroup_df=rgroup_df),
        partial(add_aromatic_interactions, pdb_df=pdb_df),
        partial(add_aromatic_sulphur_interactions, rgroup_df=rgroup_df),
        partial(add_cation_pi_interactions, rgroup_df=rgroup_df),
    ]

    G = compute_interaction_graph(pdb_df, chain_pos_aa, edge_funcs=edge_funcs)
    convert_all_sets_to_lists(G)
    return G

def compute_interaction_graph(pdb_df, chain_pos_aa, edge_funcs=None):
    """
    Compute the interaction graph.

    ## Parameters:

    - `pdb_df`: A pandas DataFrame.
        Should be the result of calling `pdb2df`.
    - `chain_pos_aa`: A nested dictionary mapping chain -> pos -> aa.
        Should be the result of calling `compute_chain_pos_aa_mapping`.
    - `edge_funcs`: Arbitrary functions which take in only a graph `G`,
        and uses `add_edge` to add edges to the graph.
    """
    # Add in nodes with their metadata
    # Metadata are:
    # - x, y, z coordinates of C-alpha
    # - chain_id
    # - residue_number
    # - residue_name
    G = nx.Graph()
    for g, d in pdb_df.query("record_name == 'ATOM'").groupby(
        ["node_id", "chain_id", "residue_number", "residue_name"]
    ):
        node_id, chain_id, residue_number, residue_name = g
        x_coord = d.query("atom_name == 'CA'")["x_coord"].values[0]
        y_coord = d.query("atom_name == 'CA'")["y_coord"].values[0]
        z_coord = d.query("atom_name == 'CA'")["z_coord"].values[0]
        G.add_node(
            node_id,
            chain_id=chain_id,
            residue_number=residue_number,
            residue_name=residue_name,
            x_coord=x_coord,
            y_coord=y_coord,
            z_coord=z_coord,
            features=None,
        )

    # Add in edges for amino acids that are adjacent in the linear amino
    # acid sequence.
    for n, d in G.nodes(data=True):
        chain = d["chain_id"]
        pos = d["residue_number"]
        aa = d["residue_name"]

        if pos - 1 in chain_pos_aa[chain].keys():
            prev_aa = chain_pos_aa[chain][pos - 1]
            prev_node = f"{chain}{pos-1}{prev_aa}"
            if aa in RESI_NAMES and prev_aa in RESI_NAMES:
                G.add_edge(n, prev_node, kind={"backbone"})

        if pos + 1 in chain_pos_aa[chain].keys():
            next_aa = chain_pos_aa[chain][pos + 1]
            next_node = f"{chain}{pos+1}{next_aa}"
            if aa in RESI_NAMES and next_aa in RESI_NAMES:
                G.add_edge(n, next_node, kind={"backbone"})

    # Add in each type of edge, based on the above.
    for func in edge_funcs:
        func(G)
    return G

def convert_all_sets_to_lists(G):
    """Convert all node and edge attributes to lists."""
    for n, d in G.nodes(data=True):
        for k, v in d.items():
            if isinstance(v, set):
                G.nodes[n][k] = list(v)

    for u1, u2, d in G.edges(data=True):
        for k, v in d.items():
            if isinstance(v, set):
                G.edges[u1, u2][k] = list(v)

def compute_distmat(pdb_df):
    """
    Compute pairwise euclidean distances between every atom.

    Design choice: passed in a DataFrame to enable easier testing on
    dummy data.
    """
    eucl_dists = pdist(
        pdb_df[["x_coord", "y_coord", "z_coord"]], metric="euclidean"
    )
    eucl_dists = pd.DataFrame(squareform(eucl_dists))
    eucl_dists.index = pdb_df.index
    eucl_dists.columns = pdb_df.index

    return eucl_dists

def compute_rgroup_dataframe(pdb_df):
    """Return the atoms that are in R-groups and not the backbone chain."""
    rgroup_df = filter_dataframe(pdb_df, "atom_name", BACKBONE_ATOMS, False)
    return rgroup_df

def filter_dataframe(dataframe, by_column, list_of_values, boolean):
    """
    Filter function for dataframe.

    Filters the [dataframe] such that the [by_column] values have to be
    in the [list_of_values] list if boolean == True, or not in the list
    if boolean == False
    """
    df = dataframe.copy()
    df = df[df[by_column].isin(list_of_values) == boolean]
    df.reset_index(inplace=True, drop=True)

    return df

def add_hydrophobic_interactions(G, rgroup_df):
    """
    Find all hydrophobic interactions.

    Performs searches between the following residues:
    ALA, VAL, LEU, ILE, MET, PHE, TRP, PRO, TYR

    Criteria: R-group residues are within 5A distance.
    """
    hydrophobics_df = filter_dataframe(
        rgroup_df, "residue_name", HYDROPHOBIC_RESIS, True
    )
    distmat = compute_distmat(hydrophobics_df)
    interacting_atoms = get_interacting_atoms(5, distmat)
    add_interacting_resis(
        G, interacting_atoms, hydrophobics_df, ["hydrophobic"]
    )

def add_disulfide_interactions(G, rgroup_df):
    """
    Find all disulfide interactions between CYS residues.

    Criteria: sulfur atom pairs are within 2.2A of each other.
    """
    disulfide_df = filter_dataframe(
        rgroup_df, "residue_name", DISULFIDE_RESIS, True
    )
    disulfide_df = filter_dataframe(
        disulfide_df, "atom_name", DISULFIDE_ATOMS, True
    )
    distmat = compute_distmat(disulfide_df)
    interacting_atoms = get_interacting_atoms(2.2, distmat)
    add_interacting_resis(G, interacting_atoms, disulfide_df, ["disulfide"])

def add_hydrogen_bond_interactions(G, rgroup_df):
    """Add all hydrogen-bond interactions."""
    # For these atoms, find those that are within 3.5A of one another.
    HBOND_ATOMS = [
        "ND",  # histidine and asparagine
        "NE",  # glutamate, tryptophan, arginine, histidine
        "NH",  # arginine
        "NZ",  # lysine
        "OD1",
        "OD2",
        "OE",
        "OG",
        "OH",
        "SD",  # cysteine
        "SG",  # methionine
        "N",
        "O",
    ]
    hbond_df = filter_dataframe(rgroup_df, "atom_name", HBOND_ATOMS, True)
    distmat = compute_distmat(hbond_df)
    interacting_atoms = get_interacting_atoms(3.5, distmat)
    add_interacting_resis(G, interacting_atoms, hbond_df, ["hbond"])

    # For these atoms, find those that are within 4.0A of one another.
    HBOND_ATOMS_SULPHUR = ["SD", "SG"]
    hbond_df = filter_dataframe(
        rgroup_df, "atom_name", HBOND_ATOMS_SULPHUR, True
    )
    distmat = compute_distmat(hbond_df)
    interacting_atoms = get_interacting_atoms(4.0, distmat)
    add_interacting_resis(G, interacting_atoms, hbond_df, ["hbond"])

def add_ionic_interactions(G, rgroup_df):
    """
    Find all ionic interactions.

    Criteria: ARG, LYS, HIS, ASP, and GLU residues are within 6A.
    """
    ionic_df = filter_dataframe(rgroup_df, "residue_name", IONIC_RESIS, True)
    distmat = compute_distmat(ionic_df)
    interacting_atoms = get_interacting_atoms(6, distmat)

    add_interacting_resis(G, interacting_atoms, ionic_df, ["ionic"])

    # Check that the interacting residues are of opposite charges
    for r1, r2 in get_edges_by_bond_type(G, "ionic"):
        condition1 = (
            G.nodes[r1]["residue_name"] in POS_AA
            and G.nodes[r2]["residue_name"] in NEG_AA
        )

        condition2 = (
            G.nodes[r2]["residue_name"] in POS_AA
            and G.nodes[r1]["residue_name"] in NEG_AA
        )

        is_ionic = condition1 or condition2
        if not is_ionic:
            G.edges[r1, r2]["kind"].remove("ionic")
            if len(G.edges[r1, r2]["kind"]) == 0:
                G.remove_edge(r1, r2)

def add_aromatic_interactions(G, pdb_df):
    """
    Find all aromatic-aromatic interaction.

    Criteria: phenyl ring centroids separated between 4.5A to 7A.

    Phenyl rings are present on PHE, TRP, HIS and TYR.

    Phenyl ring atoms on these amino acids are defined by the following
    atoms:
    - PHE: CG, CD, CE, CZ
    - TRP: CD, CE, CH, CZ
    - HIS: CG, CD, ND, NE, CE
    - TYR: CG, CD, CE, CZ

    Centroids of these atoms are taken by taking:
        (mean x), (mean y), (mean z)
    for each of the ring atoms.

    Notes for future self/developers:
    - Because of the requirement to pre-compute ring centroids, we do not
        use the functions written above (filter_dataframe, compute_distmat,
        get_interacting_atoms), as they do not return centroid atom
        euclidean coordinates.
    """
    dfs = []
    for resi in AROMATIC_RESIS:
        resi_rings_df = get_ring_atoms(pdb_df, resi)
        resi_centroid_df = get_ring_centroids(resi_rings_df)
        dfs.append(resi_centroid_df)

    aromatic_df = (
        pd.concat(dfs).sort_values(by="node_id").reset_index(drop=True)
    )

    distmat = compute_distmat(aromatic_df)
    distmat.set_index(aromatic_df["node_id"], inplace=True)
    distmat.columns = aromatic_df["node_id"]
    distmat = distmat[(distmat >= 4.5) & (distmat <= 7)].fillna(0)
    indices = np.where(distmat > 0)

    interacting_resis = []
    for i, (r, c) in enumerate(zip(indices[0], indices[1])):
        interacting_resis.append((distmat.index[r], distmat.index[c]))

    for i, (n1, n2) in enumerate(interacting_resis):
        assert G.nodes[n1]["residue_name"] in AROMATIC_RESIS
        assert G.nodes[n2]["residue_name"] in AROMATIC_RESIS
        if G.has_edge(n1, n2):
            G.edges[n1, n2]["kind"].add("aromatic")
        else:
            G.add_edge(n1, n2, kind={"aromatic"})

def add_aromatic_sulphur_interactions(G, rgroup_df):
    """Find all aromatic-sulphur interactions."""
    RESIDUES = ["MET", "CYS", "PHE", "TYR", "TRP"]
    SULPHUR_RESIS = ["MET", "CYS"]
    AROMATIC_RESIS = ["PHE", "TYR", "TRP"]

    aromatic_sulphur_df = filter_dataframe(
        rgroup_df, "residue_name", RESIDUES, True
    )
    distmat = compute_distmat(aromatic_sulphur_df)
    interacting_atoms = get_interacting_atoms(5.3, distmat)
    interacting_atoms = zip(interacting_atoms[0], interacting_atoms[1])

    for (a1, a2) in interacting_atoms:
        resi1 = aromatic_sulphur_df.loc[a1, "node_id"]
        resi2 = aromatic_sulphur_df.loc[a2, "node_id"]

        condition1 = resi1 in SULPHUR_RESIS and resi2 in AROMATIC_RESIS
        condition2 = resi1 in AROMATIC_RESIS and resi2 in SULPHUR_RESIS

        if (condition1 or condition2) and resi1 != resi2:
            if G.has_edge(resi1, resi2):
                G.edges[resi1, resi2]["kind"].add("aromatic_sulphur")
            else:
                G.add_edge(resi1, resi2, kind={"aromatic_sulphur"})

def add_cation_pi_interactions(G, rgroup_df):
    """Add cation-pi interactions."""
    cation_pi_df = filter_dataframe(
        rgroup_df, "residue_name", CATION_PI_RESIS, True
    )
    distmat = compute_distmat(cation_pi_df)
    interacting_atoms = get_interacting_atoms(6, distmat)
    interacting_atoms = zip(interacting_atoms[0], interacting_atoms[1])

    for (a1, a2) in interacting_atoms:
        resi1 = cation_pi_df.loc[a1, "node_id"]
        resi2 = cation_pi_df.loc[a2, "node_id"]

        condition1 = resi1 in CATION_RESIS and resi2 in PI_RESIS
        condition2 = resi1 in PI_RESIS and resi2 in CATION_RESIS

        if (condition1 or condition2) and resi1 != resi2:
            if G.has_edge(resi1, resi2):
                G.edges[resi1, resi2]["kind"].add("cation_pi")
            else:
                G.add_edge(resi1, resi2, kind={"cation_pi"})

def get_interacting_atoms(angstroms, distmat):
    """Find the atoms that are within a particular radius of one another."""
    return np.where(distmat <= angstroms)

def add_delaunay_triangulation(G, pdb_df):
    """
    Compute the Delaunay triangulation of the protein structure.

    This has been used in prior work. References:
    - Harrison, R. W., Yu, X. & Weber, I. T. Using triangulation to include
        target structure improves drug resistance prediction accuracy. in 1–1
        (IEEE, 2013). doi:10.1109/ICCABS.2013.6629236
    - Yu, X., Weber, I. T. & Harrison, R. W. Prediction of HIV drug
        resistance from genotype with encoded three-dimensional protein
        structure. BMC Genomics 15 Suppl 5, S1 (2014).

    Notes:
    1. We do not use the add_interacting_resis function, because this
        interaction is computed on the CA atoms. Therefore, there is code
        duplication. For now, I have chosen to leave this code duplication
        in.
    """
    ca_coords = pdb_df.query("atom_name == 'CA'")

    tri = Delaunay(
        ca_coords[["x_coord", "y_coord", "z_coord"]]
    )  # this is the triangulation
    for simplex in tri.simplices:
        nodes = ca_coords.reset_index().loc[simplex, "node_id"]

        for n1, n2 in combinations(nodes, 2):
            if G.has_edge(n1, n2):
                G.edges[n1, n2]["kind"].add("delaunay")
            else:
                G.add_edge(n1, n2, kind={"delaunay"})

def get_ring_atoms(dataframe, aa):
    """
    Return ring atoms from a dataframe.

    A helper function for add_aromatic_interactions.

    Gets the ring atoms from the particular aromatic amino acid.

    Parameters:
    ===========
    - dataframe: the dataframe containing the atom records.
    - aa: the amino acid of interest, passed in as 3-letter string.

    Returns:
    ========
    - dataframe: a filtered dataframe containing just those atoms from the
                    particular amino acid selected. e.g. equivalent to
                    selecting just the ring atoms from a particular amino
                    acid.
    """
    ring_atom_df = filter_dataframe(dataframe, "residue_name", [aa], True)

    ring_atom_df = filter_dataframe(
        ring_atom_df, "atom_name", AA_RING_ATOMS[aa], True
    )
    return ring_atom_df

def get_ring_centroids(ring_atom_df):
    """
    Return aromatic ring centrods.

    A helper function for add_aromatic_interactions.

    Computes the ring centroids for each a particular amino acid's ring
    atoms.

    Ring centroids are computed by taking the mean of the x, y, and z
    coordinates.

    Parameters:
    ===========
    - ring_atom_df: a dataframe computed using get_ring_atoms.
    - aa: the amino acid under study

    Returns:
    ========
    - centroid_df: a dataframe containing just the centroid coordinates of
                    the ring atoms of each residue.
    """
    centroid_df = (
        ring_atom_df.groupby("node_id")
        .mean()[["x_coord", "y_coord", "z_coord"]]
        .reset_index()
    )

    return centroid_df

def get_edges_by_bond_type(G, bond_type):
    """
    Return edges of a particular bond type.

    Parameters:
    ===========
    - bond_type: (str) one of the elements in the variable BOND_TYPES

    Returns:
    ========
    - resis: (list) a list of tuples, where each tuple is an edge.
    """
    resis = []
    for n1, n2, d in G.edges(data=True):
        if bond_type in d["kind"]:
            resis.append((n1, n2))
    return resis

def node_coords(G, n):
    """
    Return the x, y, z coordinates of a node.

    This is a helper function. Simplifies the code.
    """
    x = G.nodes[n]["x_coord"]
    y = G.nodes[n]["y_coord"]
    z = G.nodes[n]["z_coord"]

    return x, y, z

def add_interacting_resis(G, interacting_atoms, dataframe, kind):
    """
    Add interacting residues to graph.

    Returns a list of 2-tuples indicating the interacting residues based
    on the interacting atoms. This is most typically called after the
    get_interacting_atoms function above.

    Also filters out the list such that the residues have to be at least
    two apart.

    ### Parameters

    - interacting_atoms:    (numpy array) result from get_interacting_atoms function.
    - dataframe:            (pandas dataframe) a pandas dataframe that
                            houses the euclidean locations of each atom.
    - kind:                 (list) the kind of interaction. Contains one
                            of :
                            - hydrophobic
                            - disulfide
                            - hbond
                            - ionic
                            - aromatic
                            - aromatic_sulphur
                            - cation_pi
                            - delaunay

    Returns:
    ========
    - filtered_interacting_resis: (set of tuples) the residues that are in
        an interaction, with the interaction kind specified

    """
    # This assertion/check is present for defensive programming!
    for k in kind:
        assert k in BOND_TYPES

    resi1 = dataframe.loc[interacting_atoms[0]]["node_id"].values
    resi2 = dataframe.loc[interacting_atoms[1]]["node_id"].values

    interacting_resis = set(list(zip(resi1, resi2)))
    for i1, i2 in interacting_resis:
        if i1 != i2:
            if G.has_edge(i1, i2):
                for k in kind:
                    G.edges[i1, i2]["kind"].add(k)
            else:
                G.add_edge(i1, i2, kind=set(kind))

class ProteinGraph(nx.Graph):
    """
    The ProteinGraph object.

    Inherits from the NetworkX Graph object.

    Implements further functions for automatically computing the graph
    structure.

    Certain functions are available for integration with the
    neural-fingerprint Python package.
    """

    def __init__(self):
        """Init."""
        super(ProteinGraph, self).__init__()

        self.chain_pos_aa_mapping = compute_chain_pos_aa_mapping()

        # Mapping of chain -> position -> aa
        self.rgroup_df = self.compute_rgroup_dataframe()
        # Automatically compute the interaction graph upon loading.
        self.compute_interaction_graph()
        self.compute_all_node_features()
        self.compute_all_edge_features()

        # Convert all metadata that are set datatypes to lists.
        self.convert_all_sets_to_lists()


##########################
# --- Day 11: Hex Ed --- #
##########################

import AOCUtils

def distToOrigin(p):
    x, y = p
    if (x >= 0) == (y >= 0):
        return abs(x + y)
    else:
        return max(abs(x), abs(y))

##########################

path = AOCUtils.loadInput(11).split(",")

# X axis rotated 30 deg (L/R is SW/NE)
directions = {"nw": (-1, 1), "n": (0, 1), "ne": (1, 0),
              "sw": (-1, 0), "s": (0, -1), "se": (1, -1)}

steps = [(0, 0)]
for p in path:
    x, y = steps[-1]
    dx, dy = directions[p]
    steps.append((x+dx, y+dy))

print("Part 1: {}".format(distToOrigin(steps[-1])))
print("Part 2: {}".format(max(distToOrigin(step) for step in steps)))

AOCUtils.printTimeTaken()


class BST:
	def __init__(self, raw):
		self.tree = []
		self.tree.append([raw[0]])
		for el in raw[1:]:
			self.append(el)

	def append(self, num):
		l = 0
		el = 0
		flag = True
		while flag:
			if num <= self.tree[l][el]:
				if l == len(self.tree) - 1:
					self.tree.append([None]*(2**(l+1)))
					self.tree[l+1][el*2] = num
					flag = False
				elif self.tree[l+1][el*2] == None:
					self.tree[l+1][el*2] = num
					flag = False
				else:
					l = l + 1
					el = 2 * el
			else:
				if l == len(self.tree) - 1:
					self.tree.append([None]*(2**(l+1)))
					self.tree[l+1][el*2+1] = num
					flag = False
				elif self.tree[l+1][el*2+1] == None:
					self.tree[l+1][el*2+1] = num
					flag = False
				else:
					l = l + 1
					el = 2 * el + 1
		return (l,el)

	def __str__(self):
		treeStr = ""
		for i in self.tree:
			treeStr = treeStr + "[" + ", ".join([str( '_' if(j == None) else j ) for j in i]) + "]\n"
		return treeStr

	def dfs(self, l = 0, el = 0):
		prStr = ""
		if l < len(self.tree):
			if self.tree[l][el]:
				prStr = self.dfs(l + 1, el * 2)
				if not prStr:
					prStr = str(self.tree[l][el])
				else:
					prStr = prStr + ', ' + str(self.tree[l][el])
				r = self.dfs(l + 1, el * 2 + 1)
				if r:
					prStr = prStr + ', ' + r
				return prStr
		return None

	def bfs(self):
		bfsList = []
		for i in self.tree:
			for j in i:
				if not j == None:
					bfsList.append(j)
		return ', '.join([str(i) for i in bfsList])

if __name__ == '__main__':
	raw = eval(input('Enter the raw data as a list: '))
	bst = BST(raw)
	print('\nThe BST generated is:')
	print(bst)
	print('DFS: ',bst.dfs())
	print('BFS: ',bst.bfs())


import os
import gyrointerp.plotting as gp
from gyrointerp.paths import RESULTSDIR

PLOTDIR = os.path.join(RESULTSDIR, 'prot_vs_teff_residual')
if not os.path.exists(PLOTDIR):
    os.mkdir(PLOTDIR)
outdir = PLOTDIR

#
# many clusters, overplotted
#
all_clusters = ['Pleiades', 'Blanco-1', 'Psc-Eri', 'NGC-3532', 'Group-X', 'Praesepe', 'NGC-6811']
model_ids = ['120-Myr', '300-Myr', 'Praesepe', 'NGC-6811']
for poly_order in [7,6,5]:
    gp.plot_prot_vs_teff_residual(
        outdir, all_clusters, model_ids, poly_order=poly_order
    )

all_clusters = ['Pleiades', 'Blanco-1', 'Psc-Eri', 'NGC-3532', 'Group-X',
                'Praesepe', 'NGC-6819', 'Ruprecht-147']
model_ids = ['120-Myr', '300-Myr', 'Praesepe', '2.6-Gyr']
for poly_order in [7]:
    gp.plot_prot_vs_teff_residual(
        outdir, all_clusters, model_ids, poly_order=poly_order
    )


'''from cv2 import cv
import numpy as np'''

'''def main():

    # 1.导入图片
    img_src = cv2.imread("1.png")
    height, width = img_src.shape[:2]
    print("img width:%d height:%d" % (width, height))

    # 2.创建原图与目标图的对应点
    src_point = np.float32([[width * 0.15, 0], [width - 1, 0],
                            [0, height - 1], [width * 0.85, height - 1]])

    dst_point = np.float32([[0, 0], [width - 1, 0],
                            [0, height - 1], [width - 1, height - 1]])

    # 3.获取透视变换矩阵
    perspective_matrix = cv2.getPerspectiveTransform(src_point, dst_point)

    # 4.执行透视变换
    img_dst = cv2.warpPerspective(img_src, perspective_matrix, (width, height))

    # 5.显示结果
    cv2.imshow("img_src", img_src)
    cv2.imshow("img_dst", img_dst)

    cv2.waitKey()
    cv2.destroyAllWindows()'''
import cv2 as cv
import numpy as np

# 鼠标操作，鼠标选中源图像中需要替换的位置信息
def mouse_action(event, x, y, flags, replace_coordinate_array ):
    cv.imshow('collect coordinate', img_dest_copy)
    if event == cv.EVENT_LBUTTONUP:
        cv.circle(img_dest_copy, (x, y), 2, (0, 255, 255), -1)
        print(f'{x}, {y}')
        replace_coordinate_array.append([x, y])
def takeSecond(elem):
    return elem[1]
def main(plane_path , model_img_path):
    img_src = cv.imread(plane_path, cv.IMREAD_COLOR)
    h, w, c = img_src.shape
    plane = np.array([[x, y] for x in (0, w - 1) for y in (0, h - 1)])
    def mouse_action(event, x, y, flags, replace_coordinate_array ):
        cv.imshow('collect coordinate', img_dest_copy)
        if event == cv.EVENT_LBUTTONUP:
            cv.circle(img_dest_copy, (x, y), 2, (0, 255, 255), -1)
            print(f'{x}, {y}')
            replace_coordinate_array.append([x, y])
    img_dest = cv.imread(model_img_path, cv.IMREAD_COLOR) #背景图片
    img_dest_copy = np.tile(img_dest, 1)
    replace_coordinate = []
    cv.namedWindow('collect coordinate')
    cv.setMouseCallback('collect coordinate', mouse_action, replace_coordinate)
    while True:
        # 当采集到四个点后，可以按esc退出鼠标采集行为
        if cv.waitKey(20) == 27:
            break
    replace_coordinate.sort(key = takeSecond)
    replace_coordinate = np.array(replace_coordinate)
    matrix, mask = cv.findHomography(plane, replace_coordinate, 0)
    print(f'matrix: {matrix}')
    perspective_img = cv.warpPerspective(img_src, matrix,(img_dest.shape[1], img_dest.shape[0]))#(img_dest.shape[1], img_dest.shape[0])
    cv.imshow('img', perspective_img)

    retval, threshold_img = cv.threshold(perspective_img, 0, 255, cv.THRESH_BINARY)
    # 将降噪后的图像与之前的图像进行拼接
    cv.copyTo(src=threshold_img, mask=np.tile(threshold_img, 1), dst=img_dest)
    cv.copyTo(src=perspective_img, mask=np.tile(perspective_img, 1), dst=img_dest)
    cv.imshow('result', img_dest)
    cv.waitKey()
    cv.destroyAllWindows()

if __name__ == '__main__':
    main('w.png' , '1.png')


# Librerias
import numpy as nump
import pandas as pand
import seaborn as seans
import re
from sys import exit
from matplotlib import pyplot as plot
from matplotlib import style
from sklearn import linear_model
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import Perceptron
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC, LinearSVC
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV, cross_val_score
from sklearn.model_selection import cross_val_predict
from sklearn.metrics import confusion_matrix
from sklearn.metrics import precision_score, recall_score
from sklearn.metrics import f1_score
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import roc_curve
from sklearn.metrics  import roc_auc_score

#Recogemos los ficheros
test_df = pand.read_csv("PracticaIndividual/test.csv")
train_df = pand.read_csv("PracticaIndividual/train.csv")

#Mostramos la información
#train_df.info()

#Describe las variables
#print(train_df.describe())

#Describe las variables
#print(train_df.head(20))

#Se realiza la suma y se ordenan los valores de forma descendente cuando son "Null"
total = train_df.isnull().sum().sort_values(ascending=False)

#Sacamos los porcentajes
percent_1 = train_df.isnull().sum()/train_df.isnull().count()*100
#redondeamos el porcentaje que vamos a mostrar
percent_2 = (round(percent_1, 1)).sort_values(ascending=False)

#mostramos los valores que tienen campos con tipo Null en dos  columnas(La suma de Null por columna y % sobre el global de filas)
missing_data = pand.concat([total, percent_2], axis=1, keys=['Total', '%'])

#Muestra la suma de valores NULL y el porcentaje sobre el Total
#print(missing_data.head(11))

#nos muestra todas las cabeceras del fichero
#print(train_df.columns.values)

#dataNew = [train_df, test_df]
dataNew =  pand.concat(objs=[train_df, test_df], axis=0).reset_index(drop=True)

#Cambiar los valores de Sexo a Int
sex = {"male": 3, "female": 0}
data = [train_df, test_df]

for dataset in data:
    dataset['Sex'] = dataset['Sex'].map(sex)

#Agregamos al DataSet el sexo por la clase del pasajero para diferenciarlos

data = [train_df, test_df]
for dataset in data:
    dataset['Sex_Class']= dataset['Sex']+ dataset['Pclass']

#print(dataset['Sex_Class'].describe())

#MOSTRAR LAS MEDIAS AGRUPANDO POR EL GRUPO SEXCLASS
#print(dataset.groupby('Sex_Class').mean())

#Mostrar la relación entre la Edad y el Sexo
#AS = seans.factorplot(y="Age", x="Sex_Class", data = dataset, kind="box")
#PA = seans.factorplot(data = dataNew , x = 'Sex_Class' , y = 'Age', kind = 'box')

#Relación entre Pclass y edad
'''
facet = seans.FacetGrid(dataNew, hue="Sex_Class", aspect=4)
facet.map(seans.kdeplot,'Age',shade= True)
facet.set(xlim=(0, train_df['Age'].max()))
facet.add_legend()
plot.show()
'''

#Corrección v2 de la EDAD

def AgeImpute(df):
    Age = df[0]
    Sex_Class = df[1]

    if pand.isnull(Age):
        if Sex_Class == 1: return 41
        elif Sex_Class == 2: return 24
        elif Sex_Class == 3: return 23
        elif Sex_Class == 4: return 40
        elif Sex_Class == 5: return 30
        else: return 24
    else:
        return Age

# Edad corregida
train_df['Age'] = train_df[['Age' , 'Sex_Class']].apply(AgeImpute, axis = 1)
test_df['Age'] = test_df[['Age' , 'Sex_Class']].apply(AgeImpute, axis = 1)

#Trabajaremos ahora para sustituir los valores Null de la variable EDAD (V1)
'''
data = [train_df, test_df]

for dataset in data:
    mean = train_df["Age"].mean()
    std = test_df["Age"].std()
    is_null = dataset["Age"].isnull().sum()
    # calcula números aleatorios entre la media, std y is_null
    rand_age = nump.random.randint(mean - std, mean + std, size = is_null)
    # llena los valores de NaN en la columna de Edad con los valores aleatorios generados
    age_slice = dataset["Age"].copy()
    age_slice[nump.isnan(age_slice)] = rand_age
    dataset["Age"] = age_slice
    dataset["Age"] = train_df["Age"].astype(int)
print(train_df["Age"].isnull().sum())
'''
print(train_df.info())
print(test_df.info())

#Trabajaremos ahora para sustituir los valores Null de la variable Embarked
#print(train_df['Embarked'].describe())
common_value = 'S'
data = [train_df, test_df]

for dataset in data:
    dataset['Embarked'] = dataset['Embarked'].fillna(common_value)

#Nos deshacemos de cabina y lo volvemos un valor numerico(Cubierta-Deck) a partir de Primera letra del campo Cabin
deck = {"A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "U": 8}
data = [train_df, test_df]

for dataset in data:
    dataset['Cabin'] = dataset['Cabin'].fillna("U0")
    dataset['Deck'] = dataset['Cabin'].map(lambda x: re.compile("([a-zA-Z]+)").search(x).group())
    dataset['Deck'] = dataset['Deck'].map(deck)
    dataset['Deck'] = dataset['Deck'].fillna(0)
    dataset['Deck'] = dataset['Deck'].astype(int)

# Nos desacemos de la variable cabina al trabajar con el nuevo campo "Cubierta"
train_df = train_df.drop(['Cabin'], axis=1)
test_df = test_df.drop(['Cabin'], axis=1)

#Eliminamos el numero de pasajero solo en el fichero de entrenamiento
train_df = train_df.drop (['PassengerId'], axis = 1)

#observamos un conteo de la información del campo número de ticket
#print(train_df['Ticket'].describe())

#Eliminamos el numero de ticket
train_df = train_df.drop(['Ticket'], axis=1)
test_df = test_df.drop(['Ticket'], axis=1)

#Generaremos una suma de "familiares" en vez de trabajar por separado con ellas
#y otra variable 1,0 que nos permita saber si alguien está solo
data = [train_df, test_df]
for dataset in data:
    dataset['relatives'] = dataset['SibSp'] + dataset['Parch']
    dataset.loc[dataset['relatives'] > 0, 'not_alone'] = 0
    dataset.loc[dataset['relatives'] == 0, 'not_alone'] = 1
    dataset['not_alone'] = dataset['not_alone'].astype(int)
train_df['not_alone'].value_counts()

#Convertimos la tarifa pagada en un numero entero
data = [train_df, test_df]

for dataset in data:
    dataset['Fare'] = dataset['Fare'].fillna(0)
    dataset['Fare'] = dataset['Fare'].astype(int)

#Convertimos la variable de sexto en un valor numerico
sex = {3: 0, 0: 1}
data = [train_df, test_df]

for dataset in data:
    dataset['Sex'] = dataset['Sex'].map(sex)

#Convertimos la variable de sexto en un valor numerico
data = [train_df, test_df]
abrev = {"Mr": 1, "Miss": 2, "Mrs": 3, "Master": 4, "Rare": 5}

for dataset in data:
    # Exportar titulos
    dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False)
    # Los titulos más comunes los unificamos en un grupo númerico
    dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col','Don', 'Dr',\
                                            'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Rare')
    dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Ms', 'Miss')
    dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs')
    # Convertir a valor numérico
    dataset['Title'] = dataset['Title'].map(abrev)
    # Los que no tengan ningún titulo recogen el valor 0
    dataset['Title'] = dataset['Title'].fillna(0)
train_df = train_df.drop(['Name'], axis=1)
test_df = test_df.drop(['Name'], axis=1)

#Convertimos la puerta de embarque en un número entero
ports = {"S": 0, "C": 1, "Q": 2}
data = [train_df, test_df]

for dataset in data:
    dataset['Embarked'] = dataset['Embarked'].map(ports)

#Convertimos a Int la edad y hacemos grupos de edad de un tamaño similar
data = [train_df, test_df]
total = train_df.isnull().sum().sort_values(ascending=False)
print(test_df.info())
print(total)
test_df.head()

for dataset in data:
    dataset['Age'] = dataset['Age'].astype(int)
    dataset.loc[ dataset['Age'] <= 16, 'Age'] = 0
    dataset.loc[(dataset['Age'] > 16) & (dataset['Age'] <= 20), 'Age'] = 1
    dataset.loc[(dataset['Age'] > 20) & (dataset['Age'] <= 24), 'Age'] = 2
    dataset.loc[(dataset['Age'] > 24) & (dataset['Age'] <= 28), 'Age'] = 3
    dataset.loc[(dataset['Age'] > 28) & (dataset['Age'] <= 32), 'Age'] = 4
    dataset.loc[(dataset['Age'] > 32) & (dataset['Age'] <= 37), 'Age'] = 5
    dataset.loc[(dataset['Age'] > 37) & (dataset['Age'] <= 45), 'Age'] = 6
    dataset.loc[ dataset['Age'] > 45, 'Age'] = 7

#contamos los grupos de edad según franjas de edad de un rango total(101 a 122)
#print(train_df['Age'].value_counts())

#Buscamos que nos ayude la funcion qcut a formar lo grupos aproximados
#print(pand.qcut(train_df['Fare'], q=4))

#Agrupamos el precio que han pagado por el ticket cada persona
data = [train_df, test_df]

for dataset in data:
    dataset.loc[ dataset['Fare'] <= 7.91, 'Fare'] = 0
    dataset.loc[(dataset['Fare'] > 7.91) & (dataset['Fare'] <= 14.454), 'Fare'] = 1
    dataset.loc[(dataset['Fare'] > 14.454) & (dataset['Fare'] <= 31), 'Fare']   = 2
    dataset.loc[ dataset['Fare'] > 31, 'Fare'] = 3
    dataset['Fare'] = dataset['Fare'].astype(int)

#print(train_df['Fare'].value_counts())

#Agregamos al DataSet la edad por la clase del pasajero para diferenciarlos
data = [train_df, test_df]
for dataset in data:
    dataset['Age_Class']= dataset['Age']* dataset['Pclass']

#Generemos otro subgrupo en el DataSet que contenga el precio que paga cada persona
for dataset in data:
    dataset['Fare_Per_Person'] = dataset['Fare']/(dataset['relatives']+1)
    dataset['Fare_Per_Person'] = dataset['Fare_Per_Person'].astype(int)

#Mostrar la info tratada
#print(train_df.head(20))
#train_df.info()

#####VISUALIZACIÓN PARA ANÁLISIS DE DATOS#####

#visualización de datos con la libreria Seaborn
#print(seans.barplot(x='Pclass', y='Survived', data=train_df))

#Visualización relación clase y grupo de edad
#grid = seans.FacetGrid(train_df, col='Survived', row='Pclass', size=2.2, aspect=1.6)
#grid.map(plot.hist, 'Age', alpha=.5, bins=20)
#grid.add_legend();

#Mostramos los datos de los supervivientes por sexo
'''
survived = 'survived'
not_survived = 'not survived'
fig, axes = plot.subplots(nrows=1, ncols=2,figsize=(10, 4))
women = train_df[train_df['Sex']==0]
men = train_df[train_df['Sex']==1]
ax = seans.distplot(women[women['Survived']==1].Age.dropna(), bins=18, label = survived, ax = axes[0], kde =False)
ax = seans.distplot(women[women['Survived']==0].Age.dropna(), bins=40, label = not_survived, ax = axes[0], kde =False)
ax.legend()
ax.set_title('Female')
ax = seans.distplot(men[men['Survived']==1].Age.dropna(), bins=18, label = survived, ax = axes[1], kde = False)
ax = seans.distplot(men[men['Survived']==0].Age.dropna(), bins=40, label = not_survived, ax = axes[1], kde = False)
ax.legend()
_ = ax.set_title('Male')
'''

#Mostramos visualmente los datos de superviviencia embarcando en cada puerto
'''
FacetGrid = seans.FacetGrid(train_df, row='Embarked', size=4.5, aspect=1.6)
FacetGrid.map(seans.pointplot, 'Pclass', 'Survived', 'Sex', palette=None,  order=None, hue_order=None )
FacetGrid.add_legend()
'''

#Comprobamos la correlación entre el número de familiares
#axes = seans.factorplot('relatives','Survived',data=train_df, aspect = 2.5, )

#Mostrar los nulos y otra información sobre el DATASET Tratado
'''
print('Datos despues de tratarlos:')
print(pand.isnull(train_df).sum())
print(pand.isnull(test_df).sum())
print(train_df.shape)
print(test_df.shape)
print(test_df.head())
print(train_df.head())
'''

####BORRAMOS ATRIBUTOS PARA MEJORAR NUESTRO MODELO#####
# Estos atributos tiene poca importancia en la probabilidad de supervivencia
train_df  = train_df.drop("not_alone", axis=1)
test_df  = test_df.drop("not_alone", axis=1)
train_df  = train_df.drop("Parch", axis=1)
test_df  = test_df.drop("Parch", axis=1)

##### APLICACIÓN ALGORITMOS Y ENTRENAMIENTO #####

#Separamos la columna superviviente en otra matriz de datos y la de test sin el ID de Pasajero
X_train = train_df.drop("Survived", axis=1)
Y_train = train_df["Survived"]
X_test  = test_df.drop("PassengerId", axis=1).copy()

#Información de las variables
#print(train_df.info())
#print(test_df.info())

#Algoritmo Stochastic Gradient Descent (SGD)
sgd = linear_model.SGDClassifier(max_iter=5, tol=None)
sgd.fit(X_train, Y_train)
Y_pred = sgd.predict(X_test)

sgd.score(X_train, Y_train)

acc_sgd = round(sgd.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Stochastic Gradient Descent (SGD):',acc_sgd)

#Algoritmo Random Forest
random_forest = RandomForestClassifier(n_estimators=100)
random_forest.fit(X_train, Y_train)

Y_prediction = random_forest.predict(X_test)

random_forest.score(X_train, Y_train)
acc_random_forest = round(random_forest.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Random Forest:',acc_random_forest)

#Algoritmo Regresión Logistica
logreg = LogisticRegression()
logreg.fit(X_train, Y_train)

Y_pred = logreg.predict(X_test)

acc_log = round(logreg.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Regresión Logistica:',acc_log)

#Algoritmo K Nearest Neighbor KNN
knn = KNeighborsClassifier(n_neighbors = 3)
knn.fit(X_train, Y_train)
Y_pred = knn.predict(X_test)
acc_knn = round(knn.score(X_train, Y_train) * 100, 2)
#print('Algoritmo K Nearest Neighbor KNN:',acc_log)

#### Algoritmo Gaussian Naive Bayes
gaussian = GaussianNB()
gaussian.fit(X_train, Y_train)
Y_pred = gaussian.predict(X_test)
acc_gaussian = round(gaussian.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Gaussian Naive Bayes:',acc_gaussian)

#Algoritmo Perceptron
perceptron = Perceptron(max_iter=5)
perceptron.fit(X_train, Y_train)

Y_pred = perceptron.predict(X_test)

acc_perceptron = round(perceptron.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Perceptron:',acc_perceptron)

#Algoritmo Linear Support Vector Machine(Algoritmo maquinas de Soporte Lineal):
linear_svc = LinearSVC()
linear_svc.fit(X_train, Y_train)

Y_pred = linear_svc.predict(X_test)

acc_linear_svc = round(linear_svc.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Linear Support Vector Machine:',acc_linear_svc)

#Support Vector Machines (Algoritmo maquinas de Soporte Lineal)
svc = SVC()
svc.fit(X_train, Y_train)
Y_pred = svc.predict(X_test)
acc_svc = round(svc.score(X_train, Y_train) * 100, 2)
#print('Precisión Soporte de Vectores:',acc_svc)

#Algoritmo Decision Tree
decision_tree = DecisionTreeClassifier()
decision_tree.fit(X_train, Y_train)
Y_pred = decision_tree.predict(X_test)
acc_decision_tree = round(decision_tree.score(X_train, Y_train) * 100, 2)
#print('Algoritmo Decision Tree:',acc_decision_tree)

#Mostramos cual de los algoritmos es el más fiable en una matriz de datos

results = pand.DataFrame({
    'Model': ['Support Vector Machines', 'Linear Support Vector Machines', 'KNN', 'Regresión Logistica',
              'Random Forest', 'Naive Bayes', 'Perceptron',
              'Stochastic Gradient Decent',
              'Decision Tree'],
    'Score': [acc_linear_svc, acc_linear_svc, acc_knn, acc_log,
              acc_random_forest, acc_gaussian, acc_perceptron,
              acc_sgd, acc_decision_tree]})
result_df = results.sort_values(by='Score', ascending=False)
result_df = result_df.set_index('Score')
print(result_df.head(9))

#Afinar el algoritmo Random Forest porque es de los que mejor tasa de acierto tiene

rf = RandomForestClassifier(n_estimators=100)
scores = cross_val_score(rf, X_train, Y_train, cv=10, scoring = "accuracy")
#print("Scores:", scores)
#print("Mean:", scores.mean())
#print("Standard Deviation:", scores.std())

#Mostrar la importancia de cara atributo sobre la probabilidad de sobrevivir
#importances = pand.DataFrame({'feature':X_train.columns,'importance':nump.round(random_forest.feature_importances_,3)})
#importances = importances.sort_values('importance',ascending=False).set_index('feature')
#print(importances.head(15))

#Visualizar graficamente la importancia de los atributos del Dataset
#importances.plot.bar()

#####AFINAR EL MODELO#####

param_grid = { "criterion" : ["gini", "entropy"], "min_samples_leaf" : [1, 5, 10, 25, 50, 70], "min_samples_split" : [2, 4, 10, 12, 16, 18, 25, 35], "n_estimators": [100, 400, 700, 1000, 1500]}
rf = RandomForestClassifier(n_estimators=100, max_features='auto', oob_score=True, random_state=1, n_jobs=-1)
clf = GridSearchCV(estimator=rf, param_grid=param_grid, n_jobs=-1)
#clf.fit(X_train, Y_train)
#print(clf.bestparams)

#Nuevos parametros de Random Forest
random_forest = RandomForestClassifier(criterion = "gini",
                                       min_samples_leaf = 1,
                                       min_samples_split = 10,
                                       n_estimators=100,
                                       max_features='auto',
                                       oob_score=True,
                                       random_state=1,
                                       n_jobs=-1)

random_forest.fit(X_train, Y_train)
Y_prediction = random_forest.predict(X_test)

random_forest.score(X_train, Y_train)
#print("oob score:", round(random_forest.oob_score_, 4)*100, "%")

#####CALCULAR PRECICIÓN UTILIZANDO LOS MODELOS#####

#Matriz de Precisión
predictions = cross_val_predict(random_forest, X_train, Y_train, cv=3)
#print(confusion_matrix(Y_train, predictions))

#Precisión del modelo
#print("Precision:", precision_score(Y_train, predictions))
#print("Recall:",recall_score(Y_train, predictions))

#Puntuación F
print("Preción F",f1_score(Y_train, predictions))

#Visualizar curva de PRECISIÓN

y_scores = random_forest.predict_proba(X_train)
y_scores = y_scores[:,1]
'''
precision, recall, threshold = precision_recall_curve(Y_train, y_scores)
def plot_precision_and_recall(precision, recall, threshold):
    plot.plot(threshold, precision[:-1], "r-", label="precision", linewidth=5)
    plot.plot(threshold, recall[:-1], "b", label="recall", linewidth=5)
    plot.xlabel("threshold", fontsize=19)
    plot.legend(loc="upper right", fontsize=19)
    plot.ylim([0, 1])

plot.figure(figsize=(14, 7))
plot_precision_and_recall(precision, recall, threshold)
#plot.show()
'''

#Otra opción de visualizar la precisión
'''
def plot_precision_vs_recall(precision, recall):
    plot.plot(recall, precision, "g--", linewidth=2.5)
    plot.ylabel("recall", fontsize=19)
    plot.xlabel("precision", fontsize=19)
    plot.axis([0, 1.5, 0, 1.5])

plot.figure(figsize=(14, 7))
plot_precision_vs_recall(precision, recall)
plot.show()
'''

#Curva ROC AUC
#calcular la tasa de verdaderos positivos y la tasa de falsos positivos
'''
false_positive_rate, true_positive_rate, thresholds = roc_curve(Y_train, y_scores)
#plotting entre cada uno de ellos
def plot_roc_curve(false_positive_rate, true_positive_rate, label=None):
    plot.plot(false_positive_rate, true_positive_rate, linewidth=2, label=label)
    plot.plot([0, 1], [0, 1], 'r', linewidth=4)
    plot.axis([0, 1, 0, 1])
    plot.xlabel('False Positive Rate (FPR)', fontsize=16)
    plot.ylabel('True Positive Rate (TPR)', fontsize=16)

plot.figure(figsize=(14, 7))
plot_roc_curve(false_positive_rate, true_positive_rate)
plot.show()
'''

#Puntuación de ROC AUC
r_a_score = roc_auc_score (Y_train, y_scores)
print ("ROC-AUC-Score:", r_a_score)

#GENERAR EL NUEVO FICHERO DE PREDICCION

#Crear un DataFrame con las identificaciones de los pasajeros y nuestra predicción sobre si sobrevivieron o no.
submission = pand.DataFrame({'PassengerId':test_df['PassengerId'],'Survived':Y_prediction})

filename = 'PracticaIndividual/gender_submission.csv'

submission.to_csv(filename,index=False)

print('Saved file: ' + filename)

#EXPORTACIÓN DEL DATASET FINAL EN OTRO FICHERO CSV
#train_df.to_csv(r'PracticaIndividual/export_TRAIN_DEFINITIVO.csv', index = False, header=True)
#test_df.to_csv(r'PracticaIndividual/export_TEST_DEFINITIVO.csv', index = False, header=True)


#!/usr/bin/python3
import fileinput
from string import ascii_letters

sum_of_priorities = 0

def read_lines_to_list(f):
    lines = []
    with open(f) as intake:
        for line in intake:
            lines.append(line.strip("\n"))
    return lines

backpacks = read_lines_to_list('/home/gus/python/advent_of_code_22/day3/test.txt')

for group in range(0, len(backpacks), 3):
    backpack1 = backpacks[group].rstrip()
    backpack2 = backpacks[group+1].rstrip()
    backpack3 = backpacks[group+2].rstrip()

    same = set(backpack1) & set(backpack2) & set(backpack3)
    sum_of_priorities += ascii_letters.index(same.pop())+1

print(sum_of_priorities)


#ejercicio2
import random
def llenarLista(tam):
    lista=[]
    lista=[random.randint(2, 50) for i in range(tam)]
    return lista

lista1=llenarLista(random.randrange(5, 20))
print(lista1)
lista2=llenarLista(random.randrange(5, 20))
print(lista2)

def suma(lista):
    sum=0
    for x in lista:
        sum += x
    return sum

sumaL1=suma(lista1)
print("la suma de la lista uno", sumaL1)
sumaL2=suma(lista2)
print("la suma de la lista dos es.",sumaL2)

def maxSuma(listaUno,listaDos):
    if listaUno > listaDos:
        return f"La suma mas alta la tiene la lista uno porque fue {listaUno}"
    else:
        return f"La suma mas alta la tiene la lista Dos porque fue {listaDos}"

print(maxSuma(sumaL1, sumaL2))

def numMayor(mayorlistaUno, mayorlistaDos):
    if mayorlistaUno > mayorlistaDos:
        return f"El mayor lo tiene la lista Uno y es {mayorlistaUno}"
    elif mayorlistaUno == mayorlistaDos:
        return f"El mayor lo tiene la listas es el mismo {mayorlistaUno}, {mayorlistaDos}"
    else:
        return f"el mayor lo tiene la lista Dos y es {mayorlistaDos}"

def mayor(lista_Uno, lista_Dos):
    mayorll1=0
    mayorll2=0
    for h in lista_Uno:
        if h > mayorll1:
            mayorll1 = h
    for g in lista_Dos:
        if g > mayorll2:
            mayorll2 = g

    numeroMayor= numMayor(mayorll1, mayorll2)

    return f"{numeroMayor}"

print(mayor(lista1, lista2))

def numMenor(menorlista1, menorlista2):
    if menorlista1 > menorlista2:
        return f"El menor de las doa listas lo tiene la lista dos y es {menorlista2}"
    elif menorlista1 == menorlista2:
        return f"las dos listas tienen el mismo numero menor {menorlista1}, {menorlista2}"
    else:
        return f"el menor de las dos listas lo tine la lista uno y es {menorlista1}"

def menor(lista_uno, lista_dos):
    menorl1=1000000
    menorl2=1000000
    for j in lista_uno:
        if j < menorl1:
            menorl1 = j
    for k in lista_dos:
        if k < menorl2:
            menorl2 = k

    numeroMenor= numMenor(menorl1, menorl2)

    return f"{numeroMenor}"

print(menor(lista1, lista2))

def prom(lista):
    sum=0
    for k in lista:
        sum+=k
    promedio= sum/ len(lista)
    return promedio

promListaUno = prom(lista1)
print("el promedio de la lista uno",promListaUno)
promListaDos = prom(lista2)
print("el promedio de la lista dos es:",promListaDos)

def promConj(listaUno, listaDos):

    sumaElementos= sumaL1 + sumaL2
    sumaLong = len(listaUno) + len(listaDos)
    op = sumaElementos / sumaLong

    print(f"el promedio conjunto es : {op}")

    if promListaUno < op:
        return "El promedio de la lista Uno esta por debajo del promedio conjunto"
    elif promListaUno == op or promListaDos == op:
        return "El promedio de la lista y el conjunto son iguales"
    elif promListaDos < op:
        return "El promedio de la lista dos esta por debajo de el conjunto"
    elif promListaUno > op:
        return "El promedio de la lista uno esta por encima del conjunto"
    else:
        return "El promedio de la lista dos esta por encima del promedio conjunto"

print(promConj(lista1, lista2))

def pares(lista):
    paresCont=0
    for l in lista:
        if l % 2 == 0:
            paresCont+=1
    return paresCont

paresl1 = pares(lista1)
print(f"La lista uno tiene {paresl1} pares")
paresl2 = pares(lista2)
print(f"La lista dos tiene {paresl2} pares")

def maxPares(pares1, pares2):
    if pares1 < pares2:
        return "La lista dos tiene mas pares que la lista uno"
    elif pares1 > pares2:
        return "La lista uno tiene mas pares que lista dos"
    else:
        return "Ambos tienen la misma cantidad de pares"

print(maxPares(paresl1, paresl2))

def impares(lista):
    imparesCont=0
    for h in lista:
        if h % 2 !=0:
            imparesCont+=1
    return imparesCont
imparesl1 = impares(lista1)
print(f"La lista uno tiene {imparesl1} impares")
imparesl2 = impares(lista2)
print(f"La lista dos tiene {imparesl2} impares")

def maxImpares(impares1, impares2):
    if impares1 < impares2:
        return "La lista dos tiene mas impares que la lista uno"
    elif impares1 > impares2:
        return "La lista uno tiene mas impares que lista dos"
    else:
        return "Ambos tienen la misma cantidad de impares"

print(maxImpares(imparesl1, imparesl2))


import numpy as np
from pathlib import Path

from uq4pk_fit.blob_detection.blankets.compute_blanket import compute_blanket
from .parameters import EXAMPLE_MAP, EXAMPLE_LOWER, EXAMPLE_UPPER, SLICE_INDEX

loc = Path(__file__).parent

def one_dimensional_example():
    """
    Sets up the arrays for creating the plot that illustrated t-blankets in one dimension.
    """
    lower2d = np.load(str(loc / EXAMPLE_LOWER))
    upper2d = np.load(str(loc / EXAMPLE_UPPER))
    map2d = np.load(str(loc / EXAMPLE_MAP))
    n = lower2d.shape[1]
    lower = lower2d[SLICE_INDEX, :].reshape((n,))
    upper = upper2d[SLICE_INDEX, :].reshape((n,))
    map1d = map2d[SLICE_INDEX, :].reshape((n,))
    string = compute_blanket(lb=lower, ub=upper)
    return lower, upper, map1d, string


# coding=UTF-8

from elasticsearch import Elasticsearch
import csv
from elasticsearch import Elasticsearch
from elasticsearch import helpers
from digits2chinese import to_chinese
from chinese import four_to_han
from translate.example import connect
from translate.Baidu_Text_transAPI import translate
import json
import os.path
import csv
from tqdm import tqdm
from clear import clear
import copy
import difflib

DOC_Count = 10

def insert_QAData(doc_name, id, count):
    csv_set = []
    with open(doc_name, 'r') as csvfile:
        reader = csv.DictReader(csvfile)
        rows = csv.reader(csvfile)
        column = [row['答案'] for row in reader]
        json_set = []
        for (i,c) in enumerate(column):
            dataitem = ''
            for j in range(5):
                if i+j <len(column):
                    dataitem += column[i+j]
            dic_tmp = {"name": doc_name[2:], "para_id": count, "paragraph": dataitem}
            csv_set.append(dataitem)
            count += 1
            dicJson = json.dumps(dic_tmp, ensure_ascii=False)
            json_set.append(dicJson)

    with open(doc_name, 'r') as csvfile:
        rows = csv.reader(csvfile)
        with open('./output'+doc_name[1:], 'w') as wfile:
            writer = csv.writer(wfile)
            index = 0
            for row in rows:
                row = row[:-1]
                if index == 0:
                    index += 1
                    continue
                if index < len(csv_set):
                    row.append(csv_set[index-1])
                    index += 1
                    writer.writerow(row)
    def gendata():
        for j in json_set:
            j = eval(j)
            yield {
                "_index": "regulations",
                "name": doc_name[0:-5],
                "para_id": j["para_id"],
                "paragraph": [j["paragraph"]]
            }

    helpers.bulk(es, gendata())
    id += 1
    # csv_file = csv.writer(open('./output/docshenan.csv', 'w'))
    # for i in csv_set:
    #     csv_file.writerow([i])

def insert_json(doc_name, id):
    with open('./regulations/'+doc_name, 'rb') as csv_in:
        with open('./regulations/c'+doc_name, "w", encoding="utf-8") as csv_temp:
            for line in csv_in:
                if not line:
                    break
                else:
                    line = line.decode("utf-8", "ignore")
                    #line = str(line).splitlines(True)
                    for l in line:
                        csv_temp.write(str(l).replace('\\n', ''))
    json_set = []
    csv_set = []
    count = 1
    if doc_name != ".DS_Store" and doc_name != "c.DS_Store":
        with open('./regulations/c'+doc_name, 'r') as f:
            li = f.readlines()
            for row in li:
                samples = json.loads(row)
                for sample in samples:
                    if sample["正文"] != "" and sample["正文"] != " ":
                        #datalist = sample["正文"].split(' ')
                        datalist = clear(sample["正文"])
                        for dataitem in datalist:
                            if len(dataitem) < 30:
                                continue
                            csv_set.append(dataitem)
                            dic_tmp = {"name": doc_name, "para_id": count, "paragraph": dataitem}
                            dicJson = json.dumps(dic_tmp, ensure_ascii=False)
                            json_set.append(dicJson)
                            count += 1
        f.close()
        os.remove('./regulations/c'+doc_name)
    else:
        os.remove('./regulations/'+doc_name)

    def gendata():
        for j in json_set:
            j = eval(j)
            yield {
                "_index": "regulations",
                "name": doc_name[0:-5],
                "para_id": j["para_id"],
                "paragraph": [j["paragraph"]]
            }

    helpers.bulk(es, gendata())
    id += 1
    csv_file = csv.writer(open('./output/docs.csv', 'w'))
    for i in csv_set:
        csv_file.writerow([i])
    # dataset = []
    # for line in csv_file:
    return id, count

def insert(doc_name,id):
    with open('./regulations/'+doc_name, 'r') as f1:
        list1 = f1.readlines()
    for i in range(0, len(list1)):
        list1[i] = list1[i].rstrip('\n')
    string1 ="".join(list1)
    last1 = 0
    last2 = 0
    dic = {"title":doc_name,"paragraphs":[]}
    para_id = 1
    json_set = []
    for i in range(1,300):
        if i<101 or i % 100 == 0:
            str_cn = to_chinese(i)
        else:
            str_cn = four_to_han(i)
        last1 = last2
        last2 = string1.find("第"+str_cn+"条", last2, len(string1))
        if(last2 == -1):
            break
        else:
            if i==1:
                continue
            dic_tmp = {"name":doc_name,"para_id":para_id,"paragraph":string1[last1:last2]}
            dicJson = json.dumps(dic_tmp, ensure_ascii=False)
            json_set.append(dicJson)
            #es.index(index="regulations", doc_type="法律法规", id=id, body=dicJson)
            #dic["paragraphs"].append(dic_tmp)
            para_id += 1
            id +=1
    dic_tmp = {"name":doc_name,"para_id":para_id,"paragraph":string1[last1:len(string1)]}
    dicJson = json.dumps(dic_tmp, ensure_ascii=False)
    json_set.append(dicJson)
    #es.index(index="regulations", doc_type="法律法规", id=id, body=dicJson)

    #helpers.bulk(client=es, actions=json_set)
    def gendata():
        for j in json_set:
            j = eval(j)
            yield {
                "_index": "regulations",
                "name": doc_name[0:-4],
                "para_id":j["para_id"],
                "paragraph":[j["paragraph"]]
            }

    helpers.bulk(es, gendata())
    id +=1
    if f1:
        f1.close()
    return id

def query(question, answer):
    query_list = es.indices.analyze(index="regulations",body={'text':question,'analyzer':"ik_max_word"})
    query1 = {
        "query": {
            "bool": {
                "should": [
                    # {"match": {"paragraph": "发明创造"}},
                    # {"match": {"paragraph": "报酬"}}
                ]
            }
        }
    }
    for q in query_list['tokens']:
        query1["query"]["bool"]["should"].append({"match": {"paragraph": q['token']}})

    #,filter_path="hits.hits._source.paragraphs"
    es.indices.refresh(index="regulations")
    query = es.search(index="regulations", filter_path="hits", scroll='5m', body=query1)
    value = query["hits"]["hits"]
    results = []
    if len(value)>DOC_Count:
        for i in range(DOC_Count):
            para_score = value[i]['_score']
            dataItem = {}
            if in_answer(value[i]['_source']['paragraph'],answer,para_score):
                dataItem['is_selected'] = True
            else:
                dataItem['is_selected'] = False
            dataItem['title'] = value[i]['_source']['name']
            dataItem['paragraphs'] = value[i]['_source']['paragraph']
            results.append(dataItem)
        return results
    else:
        for i in range(len(value)):
            para_score = value[i]['_score']
            dataItem = {}
            if in_answer(value[i]['_source']['paragraph'], answer,para_score):
                dataItem['is_selected'] = True
            else:
                dataItem['is_selected'] = False
            dataItem['title'] = value[i]['_source']['name']
            dataItem['paragraphs'] = value[i]['_source']['paragraph']
            results.append(dataItem)
        return results
    # es查询出的结果第一页
    #results = query['hits']['hits']
    # es查询出的结果总量
    #print(query['__len__'])
    # if 'total' in query:
    #     #print('true')
    #     total = query['hits']['total']
    # else:
    #     #print('false')
    #     total = {'value':1}

def get_name(rootdir):
    name_list = []
    for parent, dirnames, filenames in os.walk(rootdir):
        # for dirname in dirnames:
        #     print("Parent folder:", parent)
        #     print("Dirname:", dirname)
        for filename in filenames:
            name_list.append(filename)
    return name_list

#def build_dataset(paragraphs, ):

def in_answer(para, answer, score):
    '''添加判断该条段落是否出现在答案中'''
    return answer in para

def get_answer(para, answer):
    true_start = answer[0:2]
    true_end = answer[-2:]
    start_score = 0
    end_score = 0
    new_start = 0
    new_end = len(para)-3
    for (i,p) in enumerate(para):
        if i == len(para)-1:
            break
        tmp_s_score = get_simi_score(para[i:i+2], true_start)
        tmp_e_score = get_simi_score(para[i:i+2], true_end)
        if tmp_s_score>start_score:
            start_score = tmp_s_score
            new_start = i
        if tmp_e_score>end_score:
            end_score = tmp_e_score
            new_end = i
    return para[new_start:new_end+2]

def get_simi_score(str1, str2):
    return difflib.SequenceMatcher(None, str1, str2).quick_ratio()

if __name__ == '__main__':
    es = Elasticsearch(hosts="127.0.0.1", port=9200, timeout=200)
    if (es.indices.exists(index='regulations') is not True):
        es.indices.create(index='regulations')
    else:
        es.indices.delete(index="regulations")
        es.indices.create(index='regulations')
    name_list = get_name('./regulations')
    id = 1
    count = 1
    for name in name_list:
        id, count = insert_json(name,id)
        #id+=1

    insert_QAData('./河南检务公开数据.csv', id, count)

    def gen_json(doc_name):
        dataset = []
        csv_file = csv.reader(open(doc_name, 'r'))
        for line in csv_file:
            result = query(line[1], line[2])
            data = {}
            data['documents'] = result
            data['question'] = line[1]
            data['answers'] = [line[2]]
            data['question_type'] = 'DESCRIPTION'
            data['question_id'] = line[0]
            data['fact_or_opinion'] = 'FACT'
            dataset.append(data)
        return dataset

    whole_set = []
    whole_set += gen_json('ques_test.csv')
    whole_set += gen_json('./output/河南检务公开数据.csv')

        #继续写入双向翻译后的数据
        #翻译回来后的文档需要重新寻找一次答案
        # result_new = copy.deepcopy(result)
        # ans_new = data['answers']
        # for re in result_new:
        #     query_trans = re['paragraphs']
        #     translation = translate('zh', 'en', query_trans)
        #     re_translation = translate('en', 'zh', translation)
        #     re['paragraphs'] = re_translation
        #     if(re['is_selected']):
        #         ans_new = get_answer(re_translation, data['answers'])
        # data_new = {}
        # data_new['documents'] = result_new
        # data_new['question'] = line[1]
        # data_new['answers'] = ans_new
        # data_new['question_type'] = 'DESCRIPTION'
        # data_new['question_id'] = line[0]
        # data_new['fact_or_opinion'] = 'FACT'
        # dataset.append(data_new)

    with open("./output/dataset.json", "w") as f:
        json.dump(whole_set, f,ensure_ascii=False)
    print("加载入文件完成...")

    '''还没有写问题类型、factoropinion'''


from django.db import transaction
from drf_extra_fields.fields import Base64ImageField
from rest_framework import serializers
from rest_framework.validators import UniqueTogetherValidator

from recipes.models import (AmountOfIngredient, Favorite, Ingredient, Recipe,
                            ShoppingList, Tag)
from users.serializers import CurrentUserSerializer

class IngredientSerializer(serializers.ModelSerializer):
    """Сериализация ингредиентов."""

    class Meta:
        model = Ingredient
        fields = '__all__'

class AmountOfIngredientSerializer(serializers.ModelSerializer):
    """Сериализация количества ингредиентов."""
    id = serializers.PrimaryKeyRelatedField(
        source='ingredient',
        read_only=True
    )
    name = serializers.SlugRelatedField(
        slug_field='name',
        source='ingredient',
        read_only=True
    )
    measurement_unit = serializers.SlugRelatedField(
        slug_field='measurement_unit',
        source='ingredient',
        read_only=True
    )

    class Meta:
        model = AmountOfIngredient
        fields = '__all__'

class AddAmountOfIngredientSerializer(serializers.ModelSerializer):
    """Сериализация добавления количества ингредиентов."""
    id = serializers.PrimaryKeyRelatedField(
        source='ingredient',
        queryset=Ingredient.objects.all()
    )
    amount = serializers.IntegerField()

    class Meta:
        model = AmountOfIngredient
        fields = (
            'amount',
            'id',
        )

class TagSerializer(serializers.ModelSerializer):
    """Сериализация тэгов."""

    class Meta:
        model = Tag
        fields = (
            'id',
            'name',
            'color',
            'slug'
        )
        lookup_field = 'id'
        extra_kwargs = {'url': {'lookup_field': 'id'}}

class ShortRecipeSerializer(serializers.ModelSerializer):
    """Сериализация рецептов для списка покупок."""
    image = serializers.SerializerMethodField()

    class Meta:
        model = Recipe
        fields = (
            'id',
            'name',
            'image',
            'cooking_time'
        )

    def get_image(self, obj):
        request = self.context.get('request')
        image_url = obj.image.url
        return request.build_absolute_uri(image_url)

class RecipeSerializer(serializers.ModelSerializer):
    """Сериализация рецептов. Для списка рецептов."""
    author = CurrentUserSerializer(read_only=True)
    tags = TagSerializer(read_only=True, many=True)
    ingredients = serializers.SerializerMethodField()
    is_favorited = serializers.SerializerMethodField()
    is_in_shopping_cart = serializers.SerializerMethodField()

    class Meta:
        model = Recipe
        fields = (
            'id',
            'tags',
            'author',
            'ingredients',
            'is_favorited',
            'is_in_shopping_cart',
            'name',
            'image',
            'text',
            'cooking_time',
        )

    def get_ingredients(self, obj):
        recipe = obj
        queryset = recipe.recipes_ingredients_list.all()
        return AmountOfIngredientSerializer(queryset, many=True).data

    def get_is_favorited(self, obj):
        request = self.context.get('request')
        user = request.user
        return (
            not request.user.is_anonymous
            and Favorite.objects.filter(recipe=obj, user=user).exists()
            and request is not None
        )

    def get_is_in_shopping_cart(self, obj):
        request = self.context.get('request')
        user = request.user
        return (
            request is not None
            and not request.user.is_anonymous
            and ShoppingList.objects.filter(recipe=obj, user=user).exists()
        )

class RecipeAllFieldsSerializer(serializers.ModelSerializer):
    """Сериализация рецептов для методов POST, PUT и PATCH"""
    image = Base64ImageField(use_url=True, max_length=None)
    author = CurrentUserSerializer(read_only=True)
    ingredients = AddAmountOfIngredientSerializer(many=True)
    tags = serializers.PrimaryKeyRelatedField(
        queryset=Tag.objects.all(),
        many=True
    )
    cooking_time = serializers.IntegerField()

    class Meta:
        model = Recipe
        fields = (
            'id',
            'image',
            'tags',
            'author',
            'ingredients',
            'name',
            'text',
            'cooking_time',
        )

    def create_bulk(self, recipe, ingredients_data):
        AmountOfIngredient.objects.bulk_create([AmountOfIngredient(
            ingredient=ingredient['ingredient'],
            recipe=recipe,
            amount=ingredient['amount']
        ) for ingredient in ingredients_data])

    @transaction.atomic
    def create(self, validated_data):
        request = self.context.get('request')
        ingredients_data = validated_data.pop('ingredients')
        tags_data = validated_data.pop('tags')
        recipe = Recipe.objects.create(author=request.user, **validated_data)
        recipe.save()
        recipe.tags.set(tags_data)
        self.create_bulk(recipe, ingredients_data)
        return recipe

    @transaction.atomic
    def update(self, instance, validated_data):
        ingredients_data = validated_data.pop('ingredients')
        tags_data = validated_data.pop('tags')
        AmountOfIngredient.objects.filter(recipe=instance).delete()
        self.create_bulk(instance, ingredients_data)
        instance.name = validated_data.pop('name')
        instance.text = validated_data.pop('text')
        instance.cooking_time = validated_data.pop('cooking_time')
        if validated_data.get('image') is not None:
            instance.image = validated_data.pop('image')
        instance.save()
        instance.tags.set(tags_data)
        return instance

    def to_representation(self, instance):
        data = RecipeSerializer(
            instance,
            context={'request': self.context.get('request')}
        ).data
        return data

class FavoriteSerializer(serializers.ModelSerializer):
    """Сериализация избранного."""

    class Meta:
        model = Favorite
        fields = ('user', 'recipe')
        validators = [
            UniqueTogetherValidator(
                queryset=Favorite.objects.all(),
                fields=('user', 'recipe'),
                message='Рецепт уже в избранном'
            )
        ]

    def to_representation(self, instance):
        request = self.context.get('request')
        return ShortRecipeSerializer(
            instance.recipe,
            context={'request': request}
        ).data

class ShoppingListSerializer(FavoriteSerializer):
    """Сериализация списка покупок."""

    class Meta(FavoriteSerializer.Meta):
        model = ShoppingList
        fields = ('user', 'recipe')
        validators = [
            UniqueTogetherValidator(
                queryset=ShoppingList.objects.all(),
                fields=('user', 'recipe'),
                message='Рецепт уже в списке покупок'
            )
        ]

    def to_representation(self, instance):
        request = self.context.get('request')
        return ShortRecipeSerializer(
            instance.recipe,
            context={'request': request}
        ).data


H, W = map(int, input().split())
S = [input() for _ in range(H)]

dx = [1, 0, -1, 0]
dy = [0, 1, 0, -1]

seen = [[False] * W for _ in range(H)]

def dfs(x, y):
  seen[x][y] = True
  for dir in range(4):
    x2, y2 = x, y
    while S[x2 + dx[dir]][y2 + dy[dir]] == '.':
      seen[x2][y2] = True
      x2 += dx[dir]
      y2 += dy[dir]
    if not seen[x2][y2]:
      dfs(x2, y2)

dfs(1, 1)

res = sum(row.count(True) for row in seen)
print(res)


# -*- mode: python -*-

block_cipher = None

a = Analysis(['tinyfactorio.py'],
             pathex=['C:\\Users\\iivarimo\\Dropbox\\#games\\Factorio_0.16.51'],
             binaries=[],
             datas=[('empty.ogg','.'),('empty.png','.'),('empty.ttf','.'),('upx.exe','.'),('pngquant.exe','.')],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='tinyfactorio',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=False,
          runtime_tmpdir=None,
          console=True )


from __future__ import annotations

import json
from pathlib import Path

import click
import numpy as np
from pymatgen.core import Structure
from ruamel.yaml import YAML  # TODO: use hydra

from torch_m3gnet.config import RunConfig
from torch_m3gnet.data.dataset import MaterialGraphDataset
from torch_m3gnet.model.litmodule import train_model

def load_dataset(
    path: Path,
    output_root: Path,
    cutoff: float,
    threebody_cutoff: float,
) -> MaterialGraphDataset:
    with open(path, "r") as f:
        raw_dataset = json.load(f)

    structures = []
    all_energies = []
    all_forces = []
    all_stresses = []
    for data in raw_dataset:
        structure = Structure.from_dict(data["structure"])
        structures.append(structure)
        # eV (total energy)
        all_energies.append(np.array(data["outputs"]["energy"]))
        # eV/AA, (num_sites, 3)
        all_forces.append(np.array(data["outputs"]["forces"]))
        # eV/atom, Voigt order
        # for Si, https://github.com/materialsvirtuallab/mlearn/issues/64
        # 1eV/AA^3 = 1602.1766208 kbar
        # Voigt order: xx, yy, zz, yz, zx, xy
        # VASP order: xx, yy, zz, xy, yz, zx
        vs = np.array(data["outputs"]["virial_stress"]) / 1602.1766208  # eV/AA^3
        all_stresses.append(vs[[0, 1, 2, 5, 3, 4]])

    dataset = MaterialGraphDataset(
        root=output_root,
        structures=structures,
        energies=all_energies,
        forces=all_forces,
        stresses=all_stresses,
        cutoff=cutoff,
        threebody_cutoff=threebody_cutoff,
    )

    return dataset

def load_train_dataset(
    path: Path,
    output_root: Path,
    cutoff: float,
    threebody_cutoff: float,
):
    return load_dataset(path / "training.json", output_root, cutoff, threebody_cutoff)

def load_test_dataset(
    path: Path,
    output_root: Path,
    cutoff: float,
    threebody_cutoff: float,
):
    return load_dataset(path / "test.json", output_root, cutoff, threebody_cutoff)

@click.command()
@click.option("--raw_datadir", required=True, type=str, help="Path for mlearn/data.")
@click.option(
    "--element",
    default="all",
    type=str,
    help="One of Cu, Ge, Li, Mo, Ni, Si, and all. 'all' loads the whole six datasets.",
)
@click.option("--config_path", type=str, help="Path for config json.")
@click.option("--resume_ckpt_path", default=None, type=str)
@click.option("--device", default="cpu", help="cuda or cpu")
@click.option("--num_workers", default=-1, type=int)
@click.option("--debug", is_flag=True)
def main(
    raw_datadir: str,
    element: str,
    config_path: str,
    resume_ckpt_path: str | None,
    device: str,
    num_workers: int,
    debug: bool,
):
    # TODO: use hydra
    with open(config_path, "r") as f:
        yaml = YAML()
        config_dict = yaml.load(f)
    config = RunConfig(**config_dict)

    root = Path(config.root)
    elements = ["Cu", "Ge", "Li", "Mo", "Ni", "Si"]
    if element == "all":
        raise NotImplementedError
    elif element in elements:
        train = load_train_dataset(
            path=Path(raw_datadir) / element,
            output_root=root / "train",
            cutoff=config.cutoff,
            threebody_cutoff=config.threebody_cutoff,
        )
        test = load_test_dataset(  # noqa: F841
            path=Path(raw_datadir) / element,
            output_root=root / "test",
            cutoff=config.cutoff,
            threebody_cutoff=config.threebody_cutoff,
        )
    else:
        raise ValueError(f"Dataset for specified element {element} does not exist.")

    train_model(
        config=config,
        train_and_val=(train, test),
        resume_ckpt_path=resume_ckpt_path,
        device=device,
        num_workers=num_workers,
        debug=debug,
    )

if __name__ == "__main__":
    main()


#!/usr/bin/env python
# encoding: utf-8
'''
>>> round(sqrt(3.5),2)
1.87
>>> round(sqrt(4),2)
2.0
'''

def sqrt (x):
    y = 1.0
    while abs(y * y - x) > 1e-6:
        # 根在 y 和 x/y 之间
        y = (y + x/y)/2 # 牛顿迭代法
    return y

if __name__ == '__main__':
    import doctest
    doctest.testmod()


import sys

class Map():
	def __init__(self, **kwargs):
		self.content = [[]]
		self._trueMap = [[{}]]
		self.sizeX = int(kwargs.get('x'))
		self.sizeY = int(kwargs.get('y'))
		self._tools = kwargs.get('tools')
		self._set = kwargs.get('set')
		for y in range(self.sizeY):
			self.content.append([])
			self._trueMap.append([])
			for x in range(self.sizeX):
				self._trueMap[y].append({
					"food": 0,
					"linemate": 0,
					"deraumere": 0,
					"sibur": 0,
					"mendiane": 0,
					"phiras": 0,
					"thystame": 0,
				})
				self.content[y].append(
					self.Tile(x, y)
				)

	class Tile():
		def __init__(self, x, y):
			self.content = {
				"food": [],
				"linemate": [],
				"deraumere": [],
				"sibur": [],
				"mendiane": [],
				"phiras": [],
				"thystame":[]
			}
		def add(self, index, coord):
			self.content[index].append(coord)

		def clear(self):
			self.content = {
				"food": [],
				"linemate": [],
				"deraumere": [],
				"sibur": [],
				"mendiane": [],
				"phiras": [],
				"thystame": []
			}

	def update(self):
		for y in range(self.sizeY):
			for x in range(self.sizeX):
				self.content[y][x].clear()
				for key, value in self._trueMap[y][x].items():
					for item in range(value):
						self.content[y][x].add(
							key,
							self._set.get(
								x,
								y,
								key,
								item
							)
						)

	def _getTile(self, x: str, y: str):
		try:
			cmd = self._tools.readTh.get_command().split(' ')[3:]
			return {
				"food": int(cmd[0]),
				"linemate": int(cmd[1]),
				"deraumere": int(cmd[2]),
				"sibur": int(cmd[3]),
				"mendiane": int(cmd[4]),
				"phiras": int(cmd[5]),
				"thystame": int(cmd[6])
			}
		except:
			print("Error while getting tile", file = sys.stderr)

	def _getMap(self):
		self._tools.write("mct")

	def addTile(self, cmd):
		try:
			cmd = cmd.split(' ')[1:]
			x = int (cmd[0])
			y = int (cmd[1])
			cmd = cmd[2:]
			tmp = {
				"food": int(cmd[0]),
				"linemate": int(cmd[1]),
				"deraumere": int(cmd[2]),
				"sibur": int(cmd[3]),
				"mendiane": int(cmd[4]),
				"phiras": int(cmd[5]),
				"thystame": int(cmd[6])
			}
			self._trueMap[y][x] = tmp
		except:
			print("Error while getting tile", file = sys.stderr)


# -*- coding: utf-8 -*-
import logging
import tensorflow as tf

def get_logger(filename):
    logger = logging.getLogger('logger')
    logger.setLevel(logging.DEBUG)
    logging.basicConfig(format='%(message)s', level=logging.DEBUG)
    handler = logging.FileHandler(filename)
    handler.setLevel(logging.DEBUG)
    handler.setFormatter(logging.Formatter('%(asctime)s:%(levelname)s: %(message)s'))
    logging.getLogger().addHandler(handler)
    return logger

def focal_loss(logits, labels, alpha, batch_size, epsilon=1.e-7, gamma=2.0):
    """
    样本不均衡考虑的损失函数
    """
    # (Class ,1)
    alpha = tf.constant(alpha, dtype=tf.float32)

    labels = tf.cast(labels, dtype=tf.int32)
    logits = tf.cast(logits, tf.float32)
    # (N,Class) > N*Class
    softmax = tf.reshape(tf.nn.softmax(logits), [-1])
    # (N,) > (N,) ,但是数值变换了，变成了每个label在N*Class中的位置
    labels_shift = tf.range(0, batch_size) * logits.shape[1] + labels
    # labels_shift = tf.range(0, batch_size*32) * logits.shape[1] + labels
    # (N*Class,) > (N,)
    prob = tf.gather(softmax, labels_shift)
    # 预防预测概率值为0的情况  ; (N,)
    prob = tf.clip_by_value(prob, epsilon, 1. - epsilon)
    # (Class ,1) > (N,)
    alpha_choice = tf.gather(alpha, labels)
    # (N,) > (N,)
    weight = tf.pow(tf.subtract(1., prob), gamma)
    weight = tf.multiply(alpha_choice, weight)
    # (N,) > 1
    loss = -tf.reduce_mean(tf.multiply(weight, tf.log(prob)))
    return loss


# try, except, finally

# SyntaxError
# print('hello)
# NameError
# mylisthere = [1,2,3]
# print(mylist)

try:
	# f = open('simple.txt', 'r')
	f = open('simple.txt', 'w')
	f.write("Test to write simple text!")
except IOError:
	print("Error: Could not find file or read data")
except:
	print("Error occurred but type is not known")
else:
	# this will be exceuted only if error does not occur
	print("Success")
	f.close()
finally:
	print("I always work even if error occurres")
print("hello world")


import random
class Spo2Measure:
    def __init__(self):
        self.detectPulseOximeter()

    #method for simulating detecting result
    def  detectPulseOximeter(self):
     #put code here for sensor spo2 measurement
     self.spo2=random.randint(85,100)
     self.pulseRate=random.randint(60,100)
     self.perfusionIndex=random.uniform(0.2,2.0)

    #To measure spo2
    #return spo2 and status two value as number and string
    def spo2Measurement(self):
       status="";
       print("Spo2 Measurement Result")
       print("SpO2: {}%".format(self.spo2))
       print("Pulse rate: {} bpm".format(self.pulseRate))
       print("Perfusion index: {}".format(self.perfusionIndex))

       if self.spo2 >= 95 and self.pulseRate >= 60 and self.pulseRate <= 100:
         print("Your SpO2 level is normal.")
         status="Normal"
       elif self.spo2 >= 90 and self.spo2 < 95 and self.pulseRate >= 60 and self.pulseRate <= 100:
         print("SpO2 level is slightly low .")
         status="Warning"
       elif self.spo2  < 90 or self.pulseRate < 60 or self.pulseRate > 100:
          status="Danger"
          print("SpO2 level is low and do medical treatment immediately")

       return self.spo2,status

    def spo2Info(self):
        status="";
        if self.spo2 >= 95 and self.pulseRate >= 60 and self.pulseRate <= 100:
        # print("Your SpO2 level is normal.")
         status="Normal"
        elif self.spo2 >= 90 and self.spo2 < 95 and self.pulseRate >= 60 and self.pulseRate <= 100:
        # print("SpO2 level is slightly low .")
         status="Warning"
        elif self.spo2  < 90 or self.pulseRate < 60 or self.pulseRate > 100:
          status="Danger"
         # print("SpO2 level is low and do medical treatment immediately")
        return self.spo2,status


from typing import List

class Solution:
    def subarraysDivByK(self, nums: List[int], k: int) -> int:
        ans = 0
        prefix_mod = 0
        mod_groups = [0] * k
        mod_groups[0] = 1

        for num in nums:
            prefix_mod = (prefix_mod + num % k + k) % k
            ans += mod_groups[prefix_mod]
            mod_groups[prefix_mod] += 1

        return ans

if __name__ == "__main__":
    assert Solution().subarraysDivByK(nums=[4, 5, 0, -2, -3, 1], k=5) == 7
    assert Solution().subarraysDivByK(nums=[5], k=9) == 0


from rest_framework import permissions

from rest_framework import permissions

class UserPermissionOnViewSet(permissions.BasePermission):

    def has_permission(self, request, view):
        if view.action == 'list':
            return request.user.is_authenticated() and request.user.is_admin
        elif view.action == 'create':
            return True
        elif view.action in ['retrieve', 'update', 'partial_update', 'destroy']:
            return True
        else:
            return False

    def has_object_permission(self, request, view, obj):
        # Deny actions on objects if the user is not authenticated
        if not request.user.is_authenticated():
            return False

        if view.action == 'retrieve':
            return obj == request.user or request.user.is_admin
        elif view.action in ['update', 'partial_update']:
            return obj == request.user or request.user.is_admin
        elif view.action == 'destroy':
            return request.user.is_admin
        else:
            return False

class UserPermissionOnAPIView(permissions.BasePermission):

    def has_permission(self, request, view):

        if request.method == 'GET':
            return request.user.is_authenticated
        elif request.method == 'POST':
            return True
        elif request.method in ['PUT', 'PATCH']:
            return True
        else:
            return False

    def has_object_permission(self, request, view, obj):
        # Deny actions on objects if the user is not authenticated
        if not request.user.is_authenticated:
            return False

        if request.method == 'GET':
            return obj == request.user
        elif request.method in ['PUT', 'PATCH']:
            return obj == request.user
        else:
            return False


import xlrd
def getthemin(number,mylist):
    array=mylist[number]
    for i in range(len(array)-1):
        for j in range(len(array)-1):
            if array[j][0]>array[j+1][0]:
                temp=array[j]
                array[j]=array[j+1]
                array[j+1]=temp
    return array
def getremoved(index,mylist,alist):
    index2=index[:]
    mylist2=[]
    for i in mylist:
        mylist2.append(alist[i])
    for i in index2:
         if i[1] in mylist2:
            index.remove(i)
    return index
def getzeroout(mylist):
    mylist1=mylist[:]
    for i in mylist1:
        if i[0]==0:
            mylist.remove(i)
    return mylist

data = xlrd.open_workbook("Dijkstra.xlsx")
table = data.sheets()[0]
thematrix=[]
head=[]
nrows=table.nrows
for i in range(1,nrows):
    mylist1=table.row_values(i, start_colx=1, end_colx=None)
    thematrix.append(mylist1)

head=table.row_values(0,start_colx=1,end_colx=None)
for i in range(len(thematrix)):
    for j in range(len(thematrix)):
        thematrix[i][j]=[thematrix[i][j],head[j]]

numberindex=int(input("pick a number:"))
getto=[]
getto.append(numberindex)
while len(getto)<=len(thematrix):
    a=getthemin(getto[-1],thematrix)
    b=getremoved(a,getto,head)
    c=getzeroout(b)
    try:
        d=c[0]
        e = head.index(d[1])
        getto.append(e)
        print("result")
        print(getto)
    except:
        print(getto)
        print("No result")
        break


from model.Cuenta import Cuenta
import uuid

class CuentaRepository:
    def __init__(self):
        self.list = []

    def add(self, item: Cuenta):
        self.list.append(item)

    """
    Expects an uuid.UUID("value")
    Deletes an account only if it has balance of 0
    Otherwise throw and exception
    """
    def delete(self, numero: uuid):
        for item in self.list:
            if item.numero == numero:
                if item.saldo != 0:
                    raise Exception('Cuenta con saldo distinto a 0')
                else:
                    self.list.remove(item)
                break

    def get_all(self):
        return self.list

    def get_by_nombre(self, nombre: str):
        for f in self.list:
            if nombre == f.nombre:
                return f
        return None

    def listar_cuentas(self):
        print("------------------------------------------------")
        print("Listado de Cuentas: ")
        for item in self.list:
            print(f'Cuenta numero: {item.numero}')
            print(f'Cliente: {item.cliente.nombre}')
            print(f'Creada el: {str(item.fecha_hora_alta)}')
            print(f'Saldo: ${item.saldo}\n')
        print("------------------------------------------------\n")


'''
Classes and functions common to model training, evaluation, and selection

June 2020
'''

from collections import namedtuple
import copy

import torch
import torch.nn as nn
import torch.optim as optim

ModelResults = namedtuple('ModelResults',
                          ['model', 'accuracy', 'precision', 'recall'])

def prediction_stats(preds, y):
    '''
    Return all the values in a confusion matrix for a set of predictions and
    their labels. Only for use with binary prediction tasks.

    Inputs:
    preds (torch.tensor): predicted scores not yet converted to binary
        predictions
    y (torch.tensor): true labels for each of examples being predicted

    Returns: 4-ple of floats, (number of true positives, number of false
        positives, number of true negatives, number of false negatives)
    '''
    rounded_preds = torch.round(torch.sigmoid(preds))
    true_pos = ((rounded_preds == y) & (rounded_preds == 1)).sum()
    false_pos = ((rounded_preds != y) & (rounded_preds == 1)).sum()
    true_neg = ((rounded_preds == y) & (rounded_preds == 0)).sum()
    false_neg = ((rounded_preds != y) & (rounded_preds == 0)).sum()

    return true_pos.item(), false_pos.item(), true_neg.item(), false_neg.item()

class TrainingModule():
    '''
    Class for training and evaluating PyTorch models.
    '''

    def __init__(self, model, lr, pos_weight, use_cuda, num_epochs):
        '''
        Initialize a TrainingModule.

        Inputs:
        model (torch.nn.Module): the PyTorch model to be used
        lr (float): learning rate for training
        pos_weight (float): weight to assign to positive-labeled examples during
            training
        use_cuda (bool): whether or not to use a GPU during traing/evaluation
        num_epochs (int): number of epochs to run when training
        '''
        self.model = model
        self.use_cuda = use_cuda
        if self.use_cuda:
            model = model.cuda()
        self.epochs = num_epochs

        self.optimizer = optim.Adam(self.model.parameters(), lr=lr)
        self.loss_fn = nn.BCEWithLogitsLoss(pos_weight=pos_weight)

    def train_epoch(self, iterator):
        '''
        Train the model for one epoch.

        Inputs:
        iterator (iterable): iterator over batches to train the model with in
        the epoch
        '''
        epoch_loss = 0
        epoch_tp = 0
        epoch_fp = 0
        epoch_tn = 0
        epoch_fn = 0
        self.model.train()

        for batch in iterator:
          # batch.alj_text has the texts and batch.decision_binary has the labels.

            self.optimizer.zero_grad()

            text = batch.alj_text
            target = batch.decision_binary
            if self.use_cuda:
                text = text.cuda()
                target = target.cuda()

            predictions = self.model.forward(text).squeeze()
            loss = self.loss_fn(predictions, target)

            loss.backward()
            self.optimizer.step()

            epoch_loss += loss.item()

            batch_tp, batch_fp, batch_tn, batch_fn = prediction_stats(predictions, target)
            epoch_tp += batch_tp
            epoch_fp += batch_fp
            epoch_tn += batch_tn
            epoch_fn += batch_fn

        loss = epoch_loss / (epoch_tp + epoch_tn + epoch_fp + epoch_fn)
        acc = (epoch_tp + epoch_tn) / (epoch_tp + epoch_tn + epoch_fp + epoch_fn)
        prec = ((epoch_tp) / (epoch_tp + epoch_fp) if (epoch_tp + epoch_fp) > 0
                else float('nan'))
        rec = ((epoch_tp) / (epoch_tp + epoch_fn) if (epoch_tp + epoch_fn) > 0
               else float('nan'))

        return loss, acc, prec, rec

    def train_model(self, train_iterator, dev_iterator):
        """
        Train the model for multiple epochs, and after each evaluate on the
        development set.  Return the best performing model on the basis of
        accuracy, precision, and recall.

        Inputs:
        train_iterator (iterable): iterator over batches to train the model with
        dev_iterator (iterable): iterator over batches to evaluate model
        performance and select models with
        """
        dev_accs = [0.]
        dev_precs = [0.]
        dev_recs = [0.]
        best_model_acc = None
        best_model_prec = None
        best_model_rec = None
        for epoch in range(self.epochs):
            self.train_epoch(train_iterator)
            dev_loss, dev_acc, dev_prec, dev_rec = self.evaluate(dev_iterator)
            print(f"Epoch {epoch}: Dev Accuracy: {dev_acc:.4f}; Dev Precision:",
                  f"{dev_prec:.4f}; Dev Recall: {dev_rec:.4f}; Dev Loss:{dev_loss:.4f}")
            if dev_acc > max(dev_accs) or best_model_acc is None:
                best_model_acc = ModelResults(copy.deepcopy(self.model), dev_acc, dev_prec, dev_rec)
            if dev_prec > max(dev_precs) or best_model_prec is None:
                best_model_prec = ModelResults(copy.deepcopy(self.model), dev_acc, dev_prec, dev_rec)
            if dev_rec > max(dev_recs) or best_model_rec is None:
                best_model_rec = ModelResults(copy.deepcopy(self.model), dev_acc, dev_prec, dev_rec)
            dev_accs.append(dev_acc)
            dev_precs.append(dev_prec)
            dev_recs.append(dev_rec)
        return {'accuracy': best_model_acc,
                'precision': best_model_prec,
                'recall': best_model_rec}

    def evaluate(self, iterator):
        '''
        Evaluate the performance of the model on the given examples.

        Inputs:
        iterator (iterable): iterator over batches to evaluate the model with
        '''
        epoch_loss = 0
        epoch_tp = 0
        epoch_fp = 0
        epoch_tn = 0
        epoch_fn = 0
        self.model.eval()

        with torch.no_grad():

            for batch in iterator:

                text = batch.alj_text
                target = batch.decision_binary
                if self.use_cuda:
                    text = text.cuda()
                    target = target.cuda()

                predictions = self.model.forward(text).squeeze()
                loss = self.loss_fn(predictions, target)

                epoch_loss += loss.item()

                batch_tp, batch_fp, batch_tn, batch_fn = prediction_stats(predictions, target)
                epoch_tp += batch_tp
                epoch_fp += batch_fp
                epoch_tn += batch_tn
                epoch_fn += batch_fn

        loss = epoch_loss / (epoch_tp + epoch_tn + epoch_fp + epoch_fn)
        acc = (epoch_tp + epoch_tn) / (epoch_tp + epoch_tn + epoch_fp + epoch_fn)
        prec = ((epoch_tp) / (epoch_tp + epoch_fp) if (epoch_tp + epoch_fp) > 0
                else float('nan'))
        rec = ((epoch_tp) / (epoch_tp + epoch_fn) if (epoch_tp + epoch_fn) > 0
               else float('nan'))

        return loss, acc, prec, rec


class Node:
    def __init__(self, value=None):
        self.value = value
        self.next = None #O(1)
        self.prev = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None #O(1)
        self.tail = None #O(1)
    def __iter__(self):
        node = self.head
        while node:
            yield node
            node = node.next
    #O(1) time and space complexity
    def createDLL(self, nodeValue):
        node = Node(nodeValue)
        node.prev = None
        node.next = None
        self.head = node
        self.tail  = node
        return "The DLL is created successfully."
    #O(n) time complexity, O(1) space complexity
    def insertNode(self, value, location):
        if self.head is None:
            print("The node cannot be inserted")
        else:
            newNode = Node(value)

            if location == 0:
                newNode.prev = None
                newNode.next = self.head
                self.head.prev = newNode
                self.head = newNode

            elif location == -1:
                newNode.next = None
                newNode.prev = self.tail
                self.tail.next=newNode
                self.tail = newNode

            else:
                traversalNode = self.head
                index = 0
                while index < location-1:
                    traversalNode = traversalNode.next
                    index += 1

                nextNode = traversalNode.next
                nextNode.prev = newNode
                newNode.next = nextNode
                newNode.prev = traversalNode
                traversalNode.next = newNode
    #O(n) time complexity, O(1) space complexity
    def traverseDLL(self):
        node = self.head
        while node:
            print(node.value)
            node = node.next
    #O(n) time complexity, O(1) space complexity
    def reverseTraverseDLL(self):
        node = self.tail
        while node:
            print(node.value)
            node = node.prev
    #O(n) time complexity, O(1) space complexity
    def searchDLL(self, nodeValue):
        if self.head is None:
            return "There is no node in the DLL."
        else:
            tempNode = self.head
            index = 0
            while tempNode:
                if tempNode.value == nodeValue:
                    return f"{nodeValue} was found at node {index}"
                else:
                    tempNode = tempNode.next
                    index += 1
            return "The value does not exist in the DLL"
    #O(n) time complexity, O(1) space complexity
    def deleteNode(self, location):
        if self.head == None:
            print("There is no node to delete")
        else:
            if location == 0:
                if self.head == self.tail:
                    self.head = None
                    self.tail = None
                else:
                    self.head = self.head.next
                    self.head.prev = None
            elif location == -1:
                if self.head == self.tail:
                    self.head = None
                    self.tail = None
                else:
                    self.tail = self.tail.prev
                    self.tail.next = None
            else:
                tempNode = self.head
                index = 0
                while index < location - 1:
                    tempNode = tempNode.next
                    index += 1
                tempNode.next = tempNode.next.next
                tempNode.next.prev  = tempNode
            print("The node has been deleted.")
    #O(n) time complexity, O(1) space complexity
    def deleteDLL(self):
        if self.head is None:
            print("There are no nodes in this DLL.")
        else:
            tempNode = self.head
            while tempNode:
                tempNode.prev = None
                tempNode = tempNode.next
            self.head = None
            self.tail = None
            print("The DLL has been successfully deleted.")

DLL = DoublyLinkedList()
DLL.createDLL(5)
DLL.insertNode(4, 0)
DLL.insertNode(6, -1)
DLL.insertNode(5.5, 2)
DLL.traverseDLL()
DLL.reverseTraverseDLL()
print(DLL.searchDLL(5.5))
print(DLL.searchDLL(70))
DLL.deleteNode(0)
DLL.traverseDLL()