import math
import logging
from simulation.units import *
from simulation.profiles import MassProfileNFW, MassProfileSIE
from simulation.lensing_sim import LensingSim
from astropy.cosmology import Planck15
from astropy.convolution import convolve, Gaussian2DKernel
from autograd import make_jvp

# from tqdm import *

logger = logging.getLogger(__name__)

class LensingObservationWithSubhalos:
    def __init__(
        self,
        mag_zero=25.5,
        mag_iso=22.5,
        exposure=1610.0,
        fwhm_psf=0.18,
        pixel_size=0.1,
        n_xy=64,
        f_sub=0.05,
        beta=-1.9,
        m_min_calib=1e6 * M_s,
        m_max_sub_div_M_hst_calib=0.01,
        m_200_min_sub=1e7 * M_s,
        m_200_max_sub_div_M_hst=0.01,
        M_200_sigma_v_scatter=False,
        params_eval=None,
        calculate_joint_score=False,
        calculate_msub_derivatives=False,
        calculate_sub_residuals=False,
        draw_host_mass=True,
        draw_host_redshift=True,
        draw_alignment=True,
        roi_size=2.,
    ):
        """
        Class to simulation an observation strong lensing image, with substructure sprinkled in.

        :param mag_zero: Zero-point magnitude of observation
        :param mag_iso: Magnitude of isotropic sky brightness
        :param exposure: Exposure time of observation, in seconds (including gain)
        :param fwhm_psf: FWHM of Gaussian PSF, in arcsecs
        :param pixel_size: Pixel side size, in arcsecs
        :param n_xy: Number of pixels (along x and y) of observation

        :param f_sub: Fraction of total contained mass in substructure
        :param beta: Slope in the subhaalo mass function
        :param m_min_calib: Minimum mass above which subhalo mass fraction is `f_sub`
        :param m_max_sub_div_M_hst_calib: Maximum mass below which subhalo mass fraction is `f_sub`,
            in units of the host halo mass
        :param m_200_min_sub: Lowest mass of subhalos to draw
        :param m_200_max_sub_div_M_hst: Maximum mass of subhalos to draw, in units of host halo mass

        :param M_200_sigma_v_scatter: Whether to apply lognormal scatter in sigma_v to M_200_host mapping

        :param params_eval: Parameters (f_sub, beta) for which p(x,z|params) will be calculated
        :param calculate_joint_score: Whether grad_params log p(x,z|params) will be calculated
        :param calculate_msub_derivatives: Whether to calculate derivatives of image wrt subhalos masses
        :param calculate_residuals: Whether to calculate residual images wrt subhalos
        """

        # beta = -2.0 is forbidden!
        if np.abs((beta + 2.)) < 1.e-3:
            beta = -2.001

        # Store input
        self.mag_zero = mag_zero
        self.mag_iso = mag_iso
        self.exposure = exposure
        self.fwhm_psf = fwhm_psf
        self.pixel_size = pixel_size
        self.n_xy = n_xy
        self.f_sub = f_sub
        self.beta = beta
        self.m_min_calib = m_min_calib
        self.m_max_sub_div_M_hst_calib = m_max_sub_div_M_hst_calib
        self.m_200_min_sub = m_200_min_sub
        self.m_200_max_sub_div_M_hst = m_200_max_sub_div_M_hst
        self.M_200_sigma_v_scatter = M_200_sigma_v_scatter
        self.params_eval = params_eval
        self.calculate_joint_score = calculate_joint_score
        self.draw_host_mass = draw_host_mass
        self.draw_host_redshift = draw_host_redshift
        self.draw_alignment = draw_alignment

        self.coordinate_limit = pixel_size * n_xy / 2.0

        # Draw lens properties consistent with Collett et al [1507.02657]

        # Clip lens redshift `z_l` to be less than 1; high-redshift lenses no good for our purposes!

        if self.draw_host_redshift:
            self.z_l = 2.0
            while self.z_l > 1.0:
                self.z_l = 10 ** np.random.normal(-0.25, 0.25)
        else:
            self.z_l = 10.0 ** -0.25

        if self.draw_host_mass:
            self.sigma_v = np.random.normal(225, 50)
        else:
            self.sigma_v = 225.0

        if self.draw_alignment:
            self.theta_x_0 = np.random.normal(0, 0.2)
            self.theta_y_0 = np.random.normal(0, 0.2)
        else:
            self.theta_x_0 = 0.0
            self.theta_y_0 = 0.0

        q = 1  # For now, hard-code host to be spherical

        # Fix the source properties to reasonable mean-ish values
        self.theta_s_e = 0.2
        self.z_s = 1.5
        self.mag_s = 23.0

        # Get relevant distances
        self.D_l = Planck15.angular_diameter_distance(z=self.z_l).value * Mpc
        D_s = Planck15.angular_diameter_distance(z=self.z_s).value * Mpc
        D_ls = Planck15.angular_diameter_distance_z1z2(z1=self.z_l, z2=self.z_s).value * Mpc

        # Get properties for NFW host DM halo
        if draw_host_mass:
            self.M_200_hst = self.M_200_sigma_v(self.sigma_v * Kmps, scatter=M_200_sigma_v_scatter)
        else:
            self.M_200_hst = self.M_200_sigma_v(self.sigma_v * Kmps, scatter=0.0)

        c_200_hst = MassProfileNFW.c_200_SCP(self.M_200_hst)
        r_s_hst, rho_s_hst = MassProfileNFW.get_r_s_rho_s_NFW(self.M_200_hst, c_200_hst)

        # Get properties for SIE host
        self.theta_E = MassProfileSIE.theta_E(self.sigma_v * Kmps, D_ls, D_s)

        # Don't consider configuration with subhalo fraction > 1!
        self.f_sub_realiz = 2.0
        while self.f_sub_realiz > 1.0:

            # Generate a subhalo population...
            ps = SubhaloPopulation(
                f_sub=f_sub,
                beta=beta,
                M_hst=self.M_200_hst,
                c_hst=c_200_hst,
                m_min=m_200_min_sub,
                m_max=m_200_max_sub_div_M_hst * self.M_200_hst,
                m_min_calib=m_min_calib,
                m_max_calib=m_max_sub_div_M_hst_calib * self.M_200_hst,
                theta_s=r_s_hst / self.D_l,
                theta_roi=roi_size * self.theta_E,
                theta_E=self.theta_E,
                params_eval=params_eval,
                calculate_joint_score=calculate_joint_score,
            )

            # ... and grab its properties
            self.m_subs = ps.m_sample
            self.n_sub_roi = ps.n_sub_roi
            self.theta_xs = ps.theta_x_sample
            self.theta_ys = ps.theta_y_sample
            self.f_sub_realiz = ps.f_sub_realiz
            self.n_sub_in_ring = ps.n_sub_in_ring
            self.f_sub_in_ring = ps.f_sub_in_ring
            self.n_sub_near_ring = ps.n_sub_near_ring
            self.f_sub_near_ring = ps.f_sub_near_ring

        # Convert magnitude for source and isotropic component to expected counts
        self.S_tot = self._mag_to_flux(self.mag_s, self.mag_zero)
        self.f_iso = self._mag_to_flux(self.mag_iso, self.mag_zero)

        # Set host properties. Host assumed to be at the center of the image.
        self.hst_param_dict = {"profile": "SIE", "theta_x_0": 0.0, "theta_y_0": 0.0, "theta_E": self.theta_E, "q": q}

        lens_list = [self.hst_param_dict]

        # Set subhalo properties

        for i_sub, (m, theta_x, theta_y) in enumerate(zip(self.m_subs, self.theta_xs, self.theta_ys)):
            c = MassProfileNFW.c_200_SCP(m)
            r_s, rho_s = MassProfileNFW.get_r_s_rho_s_NFW(m, c)
            sub_param_dict = {"profile": "NFW", "theta_x_0": theta_x, "theta_y_0": theta_y, "M_200": m, "r_s": r_s, "rho_s": rho_s}
            lens_list.append(sub_param_dict)

        # Set source properties
        src_param_dict = {"profile": "Sersic", "theta_x_0": self.theta_x_0, "theta_y_0": self.theta_y_0, "S_tot": self.S_tot, "theta_e": self.theta_s_e, "n_srsc": 1}

        # Set observation and global properties
        observation_dict = {
            "n_x": n_xy,
            "n_y": n_xy,
            "theta_x_lims": (-self.coordinate_limit, self.coordinate_limit),
            "theta_y_lims": (-self.coordinate_limit, self.coordinate_limit),
            "exposure": exposure,
            "f_iso": self.f_iso,
        }

        global_dict = {"z_s": self.z_s, "z_l": self.z_l}

        # Inititalize lensing class and produce lensed image
        lsi = LensingSim(lens_list, [src_param_dict], global_dict, observation_dict)

        self.image = lsi.lensed_image()
        self.image_poiss = np.random.poisson(self.image)  # Poisson fluctuate
        self.image_poiss_psf = self._convolve_psf(self.image_poiss, fwhm_psf, pixel_size)  # Convolve with PSF

        # Augmented data
        self.joint_log_probs = ps.joint_log_probs
        self.joint_scores = ps.joint_scores

        # Optionally, compute derivatives of image wrt each subahlo mass (takes ~1s/subhalo)
        if calculate_msub_derivatives:
            self._calculate_derivs()

        # Optionally, compute derivatives of image wrt each subahlo mass (takes ~1s/subhalo)
        if calculate_sub_residuals:
            self._calculate_residuals()

    def _calculate_residuals(self):
        """
        Compute residual images wrt each subhalo
        """

        # Recompute base image (mostly for debugging, but doesn't take much time)
        self.image_0 = self._deriv_helper_function(self.m_subs)

        # Initialize subhalo properties
        self.theta_xs_0 = self.theta_xs
        self.theta_ys_0 = self.theta_ys
        self.m_subs_0 = self.m_subs

        # Residual image array
        self.resid_sub_image = np.zeros((self.n_sub_roi, self.n_xy, self.n_xy))

        # Loop over subhalos, deleting corresponding subhalo properties andc computing residual image
        for i_sub in range(self.n_sub_roi):
            self.theta_xs = np.delete(self.theta_xs_0, i_sub)
            self.theta_ys = np.delete(self.theta_ys_0, i_sub)
            self.m_subs = np.delete(self.m_subs_0, i_sub)
            self.resid_sub_image[i_sub] = self.image_0 - self._deriv_helper_function(self.m_subs)

        # Reset subhalo properties to the original ones
        self.theta_xs = self.theta_xs_0
        self.theta_ys = self.theta_ys_0
        self.m_subs = self.m_subs_0

    def _calculate_derivs(self):
        """
        Compute derivatives of the lensing image wrt the mass of each subhalo, evaluated at the given mass
        """

        # Initialize subhalo properties
        self.theta_xs_0 = self.theta_xs
        self.theta_ys_0 = self.theta_ys
        self.m_subs_0 = self.m_subs

        # Gradient image array
        self.grad_msub_image = np.zeros((self.n_sub_roi, self.n_xy, self.n_xy))

        # Loop over subhalos, setting the first element of subhalo properties arrays to a given subhalo,
        # then compute Jacobian (hacky, but seems to be fastest way currently with forward-pass Jacobian
        # vector product implementation in autograd...
        for i_sub in range(self.n_sub_roi):
            self.theta_xs[[0, i_sub]] = self.theta_xs[[i_sub, 0]]
            self.theta_ys[[0, i_sub]] = self.theta_ys[[i_sub, 0]]
            self.m_subs[[0, i_sub]] = self.m_subs[[i_sub, 0]]

            self.grad_msub_image[i_sub] = make_jvp(self._deriv_helper_function)(self.m_subs)([1.])[1]

        # Reset subhalo properties to the original ones
        self.theta_xs = self.theta_xs_0
        self.theta_ys = self.theta_ys_0
        self.m_subs = self.m_subs_0

    def _deriv_helper_function(self, m_subs):
        """
        Helper function for autograd to compute gradients and residuals
        """

        lens_list = [self.hst_param_dict]

        # Set subhalo properties
        for m, theta_x, theta_y in zip(m_subs, self.theta_xs, self.theta_ys):
            c = MassProfileNFW.c_200_SCP(m)
            r_s, rho_s = MassProfileNFW.get_r_s_rho_s_NFW(m, c)
            sub_param_dict = {"profile": "NFW", "theta_x_0": theta_x, "theta_y_0": theta_y, "M_200": m, "r_s": r_s, "rho_s": rho_s}
            lens_list.append(sub_param_dict)

        # Set source properties
        src_param_dict = {"profile": "Sersic", "theta_x_0": self.theta_x_0, "theta_y_0": self.theta_y_0, "S_tot": self.S_tot, "theta_e": self.theta_s_e, "n_srsc": 1}

        # Set observation and global properties
        observation_dict = {
            "n_x": self.n_xy,
            "n_y": self.n_xy,
            "theta_x_lims": (-self.coordinate_limit, self.coordinate_limit),
            "theta_y_lims": (-self.coordinate_limit, self.coordinate_limit),
            "exposure": self.exposure,
            "f_iso": self.f_iso,
        }

        global_dict = {"z_s": self.z_s, "z_l": self.z_l}

        # Inititalize lensing class and produce lensed image
        lsi = LensingSim(lens_list, [src_param_dict], global_dict, observation_dict)

        return lsi.lensed_image()

    def _convolve_psf(self, image, fwhm_psf=0.18, pixel_size=0.1):
        """
        Convolve input map of pixel_size with Gaussian PSF of with FWHM `fwhm_psf`
        """
        sigma_psf = fwhm_psf / 2 ** 1.5 * np.sqrt(np.log(2))  # Convert FWHM to standard deviation
        kernel = Gaussian2DKernel(x_stddev=1.0 * sigma_psf / pixel_size)

        return convolve(image, kernel)

    def _mag_to_flux(self, mag, mag_zp):
        """
        Returns total flux of the integrated profile corresponding to magnitude `mag`, in ADU relative to `mag_zp`
        """
        return 10 ** (-0.4 * (mag - mag_zp))

    @classmethod
    def M_200_sigma_v(cls, sigma_v, scatter=False):
        """
        Relate central velocity dispersion to halo virial mass
        From https://arxiv.org/pdf/1804.04492.pdf
        """
        a = 0.09
        b = 3.48
        if scatter:
            sigma_log10_M_200 = 0.13  # Lognormal scatter
            log10_M_200 = np.random.normal(a + b * np.log10(sigma_v / (100 * Kmps)), sigma_log10_M_200)
        else:
            log10_M_200 = a + b * np.log10(sigma_v / (100 * Kmps))
        return (10 ** log10_M_200) * 1e12 * M_s

class SubhaloPopulation:
    def __init__(
        self,
        f_sub=0.15,
        beta=-1.9,
        m_min=1e7 * M_s,
        m_max=1e11 * M_s,
        m_min_calib=1e7 * M_s,
        m_max_calib=1e11 * M_s,
        theta_roi=2.5,
        M_hst=1e14 * M_s,
        theta_s=1e-4,
        c_hst=6.0,
        theta_E=1.0,
        params_eval=None,
        calculate_joint_score=False,
    ):
        """
        Calibrate number of subhalos and generate a mass sample within lensing ROI

        SHMF is assumed to have the form
        dn/dm =  M_hst/M_0 * alpha * (m / m_0) ^ beta
        with M_0 = M_MW and m_0 = 1e9 * M_s. Note that this is slightly different
        from what's in the draft at the moment.

        :param f_sub: Fraction of mass contained in substructure
        :param beta: Slope of subhalo mass function
        :param m_min: Minimum mass of subhalos
        :param m_max: Maximum mass of subhalos
        :param theta_roi: Radius of lensing ROI, in arcsecs
        :param M_hst: Host halo mass
        :param theta_s: Angular scale radius of host halo, in rad
        :param c_hst: Concentration parameter of host halo
        :param params_eval: Parameters (f_sub, beta) for which p(x,z|params) will be calculated
        :param calculate_joint_score: Whether grad_params log p(x,z|params) will be calculated
        """

        # Store settings
        self.f_sub = f_sub
        self.beta = beta
        self.m_min = m_min
        self.m_max = m_max
        self.m_min_calib = m_min_calib
        self.m_max_calib = m_max_calib
        self.theta_roi = theta_roi
        self.M_hst = M_hst
        self.theta_s = theta_s
        self.theta_E = theta_E
        self.c_hst = c_hst

        # Alpha corresponding to calibration configuration
        self.alpha = self._alpha_f_sub(f_sub, beta, m_min_calib, m_max_calib)

        # Total expected number of subhalos within virial radius of host halo
        self.n_sub_tot = self._n_sub(m_min, m_max, M_hst, self.alpha, self.beta)

        # Fraction and number of subhalos within lensing region of interest specified by theta_roi
        self.f_sub_roi = max(MassProfileNFW.M_cyl_div_M0(self.theta_roi * asctorad / theta_s), 0.0)
        self.n_sub_roi = np.random.poisson(self.f_sub_roi * self.n_sub_tot)
        logger.debug("%s subhalos (%s expected)", self.n_sub_roi, self.f_sub_roi * self.n_sub_tot)

        # Sample of subhalo masses drawn from subhalo mass function
        self.m_sample = self._draw_m_sub(self.n_sub_roi, self.m_min, self.m_max, self.beta)

        # Fraction of halo mass in subhalos, for diagnostic purposes
        self.M_hst_roi = M_hst * MassProfileNFW.M_cyl_div_M0(self.theta_roi * asctorad / self.theta_s)
        self.f_sub_realiz = np.sum(self.m_sample) / self.M_hst_roi
        logger.debug("%s substructure fraction (%s expected)", self.f_sub_realiz, self.f_sub)

        # Sample subhalo positions uniformly within ROI
        self.theta_x_sample, self.theta_y_sample = self._draw_sub_coordinates(self.n_sub_roi, r_max=self.theta_roi)

        # For debugging: subhalos within Einstein ring and near it
        self.n_sub_in_ring, self.f_sub_in_ring = self._count_subhalos_in_radius_range(0.0, 0.9 * self.theta_E)
        self.n_sub_near_ring, self.f_sub_near_ring = self._count_subhalos_in_radius_range(0.9 * self.theta_E, 1.1 * self.theta_E)

        # Calculate augmented data
        self.joint_log_probs = self._calculate_joint_log_probs(params_eval)
        if calculate_joint_score:
            self.joint_scores = self._calculate_joint_scores(params_eval[:2, :])
        else:
            self.joint_scores = None

    @staticmethod
    def _alpha_calib(m_min_calib, m_max_calib, n_calib, M_calib, beta, M_0=M_MW, m_0=1e9 * M_s):
        """
        Get normalization alpha corresponding calibration configuration specified by {n_calib, beta}
        """
        alpha = (n_calib * (-1 - beta) * M_0 / M_calib * m_0 ** beta) / (-m_max_calib ** (1.0 + beta) + m_min_calib ** (1.0 + beta))
        return alpha

    @staticmethod
    def _alpha_f_sub(f_sub, beta, m_min, m_max, M_0=M_MW, m_0=1e9 * M_s):
        """
        Get normalization alpha corresponding calibration configuration specified by {f_sub, beta}
        """
        alpha = f_sub * ((2 + beta) * M_0 * m_0 ** beta) / (m_max ** (beta + 2) - m_min ** (beta + 2))
        return alpha

    @staticmethod
    def _m_in_sub(M_hst, alpha, beta, m_min, m_max, M_0=M_MW, m_0=1e9 * M_s):
        return M_hst * alpha * (m_max ** (beta + 2) - m_min ** (beta + 2)) / ((2 + beta) * M_0 * m_0 ** beta)

    @staticmethod
    def _n_sub(m_min, m_max, M, alpha, beta, M_0=M_MW, m_0=1e9 * M_s):
        """
        Get (expected) number of subhalos between m_min, m_max
        """

        # n_sub = alpha * M * (m_max * m_min / m_0) ** beta * (m_max ** -beta * m_min - m_max * m_min ** -beta)
        # / (M_0 * (-1 + -beta))
        # ... overflows sometimes

        n_sub = alpha / (-beta - 1.0) * m_0 * M / M_0
        n_sub *= (m_min / m_0) ** (beta + 1.0) - (m_max / m_0) ** (beta + 1.0)
        return max(n_sub, 0.0)

    @staticmethod
    def _draw_m_sub(n_sub, m_sub_min, m_sub_max, beta):
        """
        Draw subhalo masses from SHMF with slope `beta` and min/max masses `m_sub_min` and `m_sub_max` . Stolen from:
        https://stackoverflow.com/questions/31114330/python-generating-random-numbers-from-a-power-law-distribution
        """
        u = np.random.uniform(0, 1, size=n_sub)
        m_low_u, m_high_u = m_sub_min ** (beta + 1), m_sub_max ** (beta + 1)
        return (m_low_u + (m_high_u - m_low_u) * u) ** (1.0 / (beta + 1.0))

    @staticmethod
    def _draw_sub_coordinates(n_sub, r_min=0.0, r_max=2.5):
        """
        Draw subhalo n_sub coordinates uniformly within a ring r_min < r < r_max
        """
        x_sub = []
        y_sub = []
        while len(x_sub) < n_sub:
            x_candidates = np.random.uniform(low=-r_max, high=r_max, size=n_sub - len(x_sub))
            y_candidates = np.random.uniform(low=-r_max, high=r_max, size=n_sub - len(x_sub))
            r2 = x_candidates ** 2 + y_candidates ** 2
            good = (r2 <= r_max ** 2) * (r2 >= r_min ** 2)
            x_sub += list(x_candidates[good])
            y_sub += list(y_candidates[good])

        return np.array(x_sub), np.array(y_sub)

    def _count_subhalos_in_radius_range(self, min_r, max_r):
        r = ((self.theta_x_sample ** 2 + self.theta_y_sample ** 2) ** 0.5).flatten()
        filter = (r >= min_r) * (r < max_r)
        n_sub = np.sum(filter.astype(np.int))
        m_sub = np.sum(self.m_sample[filter])
        f_sub = m_sub / self.M_hst_roi
        return n_sub, f_sub

    def _calculate_joint_log_probs(self, params_eval):
        """
        Calculates log p(self.n_sub_roi, self.m_sample | f_sub, beta)
        """
        if params_eval is None:
            params_eval = []

        log_probs = [0.0 for _ in params_eval]

        for i_eval, (f_sub, beta) in enumerate(params_eval):
            # Poisson term
            log_probs[i_eval] += self._log_p_n_sub(self.n_sub_roi, f_sub, beta)

            # Power law for subhalo masses
            for m_sub in self.m_sample:
                log_probs[i_eval] += self._log_p_m_sub(m_sub, beta)

        return np.array(log_probs)

    def _calculate_joint_scores(self, params, eps0=1.0e-5, eps1=1.0e-3):
        """
        Calculates grad_(f_sub, beta) log p(self.n_sub_roi, self.m_sample | f_sub, beta)
        """
        joint_scores = []

        for param in params:
            eps_vec0 = np.asarray(param).flatten() + np.array([eps0, 0.0]).reshape(1, 2)
            eps_vec1 = np.asarray(param).flatten() + np.array([0.0, eps1]).reshape(1, 2)
            param = np.asarray(param).reshape(1, 2)
            all_params = np.vstack([param, eps_vec0, eps_vec1])
            log_probs = self._calculate_joint_log_probs(all_params)

            score0 = (log_probs[1] - log_probs[0]) / eps0
            score1 = (log_probs[2] - log_probs[0]) / eps1

            joint_scores.append([score0, score1])

        return np.array(joint_scores)

    def _log_p_n_sub(self, n_sub, f_sub, beta, include_constant=False, eps=1.0e-6):
        """
        Calculates log p(n_sub | f_sub, beta)
        """
        alpha = self._alpha_f_sub(f_sub, beta, self.m_min_calib, self.m_max_calib)
        expected_n_sub = self.f_sub_roi * self._n_sub(self.m_min, self.m_max, self.M_hst, alpha, beta)
        if expected_n_sub <= eps:
            logger.warning("Expected number of subs in RoI for f_sub = %s and beta = %s is %s, setting to %s", f_sub, beta, expected_n_sub, eps)
            expected_n_sub = eps

        log_p_poisson = n_sub * np.log(expected_n_sub) - expected_n_sub
        if include_constant:
            log_p_poisson = log_p_poisson - np.log(math.factorial(n_sub))
        return log_p_poisson

    def _log_p_m_sub(self, m, beta, m_0=1e9 * M_s):
        """
        Calculates log p(m_i | beta)
        """
        if m < self.m_min or m > self.m_max:
            logger.warning("Calculating probability for subhalo mass out of bounds -- this should not happen")
            return 0.0

        log_p = beta * np.log(m / m_0)
        log_p += np.log(-beta - 1.0)
        log_p -= np.log(m_0)
        log_p -= np.log((self.m_min / m_0) ** (beta + 1.0) - (self.m_max / m_0) ** (beta + 1.0))

        if not np.isfinite(log_p):
            logger.warning("Infinite log p(m_sub | beta):")
            logger.warning("  m       = %s", m)
            logger.warning("  beta    = %s", beta)
            logger.warning("  m_0     = %s", m_0)
            logger.warning("  m_min   = %s", self.m_min)
            logger.warning("  m_max   = %s", self.m_max)
            logger.warning("  term 1  = %s", beta * np.log(m / m_0))
            logger.warning("  term 2  = %s", np.log(-beta - 1.0))
            logger.warning("  term 3  = %s", -np.log(m_0))
            logger.warning("  term 4  = %s", -np.log((self.m_min / m_0) ** (beta + 1.0) - (self.m_max / m_0) ** (beta + 1.0)))
            logger.warning("  term 4a = %s", (self.m_min / m_0) ** (beta + 1.0))
            logger.warning("  term 4b = %s", -(self.m_max / m_0) ** (beta + 1.0))

        return log_p


"""Defines string names and create queries for tables and corresponding dataset file.
"""

AGENCY = "agency"
CALENDAR = "calendar"
CALENDAR_DATES = "calendar_dates"
FREQUENCIES = "frequencies"
ROUTES = "routes"
SERVICE_ALERTS = "service_alerts"
SHAPES = "shapes"
STOP_TIMES = "stop_times"
STOPS = "stops"
TRANSFERS = "transfers"
TRIPS = "trips"

CREATE_AGENCY = (
    f"CREATE table IF NOT EXISTS {AGENCY} ("
    "agency_id int primary key, "
    "agency_name text, "
    "agency_url text, "
    "agency_timezone text, "
    "agency_lang text, "
    "agency_phone text)"
)

CREATE_CALENDAR = (
    f"CREATE table IF NOT EXISTS {CALENDAR} ("
    "service_id int primary key, "
    "monday int, "
    "tuesday int, "
    "wednesday int, "
    "thursday int, "
    "friday int, "
    "saturday int, "
    "sunday int, "
    "start_date timestamp without time zone, "
    "end_date timestamp without time zone) "
)

CREATE_CALENDAR_DATES = (
    f"CREATE table IF NOT EXISTS {CALENDAR_DATES} ("
    "service_id int primary key, "
    "date timestamp without time zone, "
    "exception_type int)"
)

CREATE_FREQUENCIES = (
    f"CREATE table IF NOT EXISTS {FREQUENCIES} ("
    "trip_id int primary key, "
    "start_time timestamp without time zone, "
    "end_time timestamp without time zone, "
    "headway_secs int, "
    "exact_times array(timestamp without time zone))"
)

CREATE_ROUTES = (
    f"CREATE table IF NOT EXISTS {ROUTES} ("
    "route_id text primary key, "
    "agency_id int, "
    "route_short_name text, "
    "route_long_name text, "
    "route_type int, "
    "route_color text, "
    "route_text_color text, "
    "route_desc text)"
)

CREATE_SERVICE_ALERTS = (
    f"CREATE table IF NOT EXISTS {SERVICE_ALERTS} ("
    "gtfs_realtime_version text, "
    "incrementality text, "
    "timestamp int)"
)

CREATE_SHAPES = (
    f"CREATE table IF NOT EXISTS {SHAPES} ("
    "shape_id int, "
    "shape_pt_location geo_point, "
    "shape_pt_sequence int)"
)

# Using arrival and departure time as text as time strings seem to be malformed
# some e.g. 24:06:00, time greater than 24 hours? May be its an interval,
# I am not very sure so using text for now.
CREATE_STOP_TIMES = (
    f"CREATE table IF NOT EXISTS {STOP_TIMES} ("
    "trip_id int, "
    "arrival_time text, "
    "departure_time text, "
    "stop_id text, "
    "stop_sequence int, "
    "pickup_type int, "
    "drop_off_type int, "
    "stop_headsign text)"
)

CREATE_STOPS = (
    f"CREATE table IF NOT EXISTS {STOPS} ("
    "stop_id text primary key, "
    "stop_code text, "
    "stop_name text, "
    "stop_desc text, "
    "stop_location geo_point, "
    "location_type double precision, "
    "parent_station text, "
    "wheelchair_boarding text, "
    "platform_code text, "
    "zone_id text)"
)

CREATE_TRANSFERS = (
    f"CREATE table IF NOT EXISTS {TRANSFERS} ("
    "from_stop_id text, "
    "to_stop_id text, "
    "transfer_type int, "
    "min_transfer_time real, "
    "from_route_id text, "
    "to_route_id text, "
    "from_trip_id int, "
    "to_trip_id int)"
)

CREATE_TRIPS = (
    f"CREATE table IF NOT EXISTS {TRIPS} ("
    "route_id text, "
    "service_id int, "
    "trip_id int, "
    "trip_headsign text, "
    "trip_short_name text, "
    "direction_id int, "
    "block_id int, "
    "shape_id int, "
    "wheelchair_accessible boolean, "
    "bikes_allowed boolean)"
)

TABLES = [
    AGENCY,
    CALENDAR,
    CALENDAR_DATES,
    FREQUENCIES,
    ROUTES,
    SERVICE_ALERTS,
    SHAPES,
    STOP_TIMES,
    STOPS,
    TRANSFERS,
    TRIPS,
]

CREATE_TABLE_QUERIES = {
    AGENCY: CREATE_AGENCY,
    CALENDAR: CREATE_CALENDAR,
    CALENDAR_DATES: CREATE_CALENDAR_DATES,
    FREQUENCIES: CREATE_FREQUENCIES,
    ROUTES: CREATE_ROUTES,
    SERVICE_ALERTS: CREATE_SERVICE_ALERTS,
    SHAPES: CREATE_SHAPES,
    STOP_TIMES: CREATE_STOP_TIMES,
    STOPS: CREATE_STOPS,
    TRANSFERS: CREATE_TRANSFERS,
    TRIPS: CREATE_TRIPS,
}


class account:
    def register(self,regno,accno,bal,pin):
        f=open(str(pin)+".txt","w")
        f.write("regno,accno,bal\n")
        f.write(str(regno)+","+str(accno)+","+str(bal))
        print("new file created with the name" +str(pin)+".txt")
    def deposit(self,pin,damount):
        f=open(str(pin)+".txt","r")
        y=[]
        j=0
        for i in f:
            x=i.split(',')
            print("ohh",x)
            if not y:
                y=x
                #print("poh",y)
            if j==0:
                j=1
            else:
                k=int(x[2])
                newamount=k+damount
                print(newamount)
                x[2]=str(newamount)
        f1=open(str(pin)+".txt","w")
        f1.write(y[0]+','+y[1]+','+y[2])
        f1.write(x[0]+','+x[1]+','+x[2])
        f.close()
        f1.close()
    def withdraw(self,pin,wamount):
        f=open(str(pin)+".txt","r")
        y=[]
        j=0
        for i in f:
            x=i.split(',')
            print(x)
            if not y:
                y=x
            if j==0:
                j=1
            else:
                k=int(x[2])
                if k<=1000:
                    print("balance is law")
                else:
                    newamount=k-wamount
                    print(newamount)
                    x[2]=str(newamount)
        f1=open(str(pin)+".txt","w")
        f1.write(y[0]+','+y[1]+','+y[2])
        f1.write(x[0]+','+x[1]+','+x[2])
        f.close()
        f1.close()
obj=account()

#obj.register(1234,66666,1000,2000)
x=int(input("enter the deposit amount"))
obj.deposit(2000,x)
y=int(input("enter the withdraw amount"))
obj.withdraw(2000,y)


import pytest
from django.core.exceptions import ValidationError

from machina.apps.forum.signals import forum_moved
from machina.core.db.models import get_model
from machina.test.context_managers import mock_signal_receiver
from machina.test.factories import (
    PostFactory, UserFactory, build_category_forum, build_link_forum, create_category_forum,
    create_forum, create_link_forum, create_topic
)

Forum = get_model('forum', 'Forum')
Post = get_model('forum_conversation', 'Post')
Topic = get_model('forum_conversation', 'Topic')

@pytest.mark.django_db
class TestForum(object):
    @pytest.fixture(autouse=True)
    def setup(self):
        self.u1 = UserFactory.create()

        # Set up top-level forums: a category, a default forum and a link forum
        self.top_level_cat = create_category_forum()
        self.top_level_forum = create_forum()
        self.top_level_link = create_link_forum()

    def test_has_a_margin_level_two_times_greater_than_its_real_level(self):
        # Run
        sub_level_forum = create_forum(parent=self.top_level_forum)
        # Check
        assert self.top_level_forum.margin_level == 0
        assert sub_level_forum.margin_level == 2

    def test_category_cannot_be_the_child_of_another_category(self):
        # Run & check
        with pytest.raises(ValidationError):
            cat = build_category_forum(parent=self.top_level_cat)
            cat.full_clean()

    def test_can_not_be_the_child_of_a_forum_link(self):
        # Run & check
        for forum_type, _ in Forum.TYPE_CHOICES:
            with pytest.raises(ValidationError):
                forum = build_link_forum(parent=self.top_level_link)
                forum.full_clean()

    def test_must_have_a_link_in_case_of_a_link_forum(self):
        # Run & check
        with pytest.raises(ValidationError):
            forum = Forum(parent=self.top_level_forum, name='sub_link_forum', type=Forum.FORUM_LINK)
            forum.full_clean()

    def test_saves_its_numbers_of_posts_and_topics(self):
        # Run & check
        topic = create_topic(forum=self.top_level_forum, poster=self.u1)
        PostFactory.create(topic=topic, poster=self.u1)
        PostFactory.create(topic=topic, poster=self.u1)
        assert self.top_level_forum.direct_posts_count == topic.posts.filter(approved=True).count()
        assert self.top_level_forum.direct_topics_count == self.top_level_forum.topics.count()

        topic2 = create_topic(forum=self.top_level_forum, poster=self.u1, approved=False)
        PostFactory.create(topic=topic2, poster=self.u1, approved=False)
        assert self.top_level_forum.direct_posts_count == \
            topic.posts.filter(approved=True).count() + topic2.posts.filter(approved=True).count()
        assert self.top_level_forum.direct_topics_count == \
            self.top_level_forum.topics.filter(approved=True).count()

    def test_can_indicate_its_appartenance_to_a_forum_type(self):
        # Run & check
        assert self.top_level_cat.is_category
        assert self.top_level_forum.is_forum
        assert self.top_level_link.is_link

    def test_stores_its_last_post_datetime(self):
        # Setup
        sub_level_forum = create_forum(parent=self.top_level_forum)
        topic = create_topic(forum=sub_level_forum, poster=self.u1)
        PostFactory.create(topic=topic, poster=self.u1)
        # Run
        p2 = PostFactory.create(topic=topic, poster=self.u1)
        # Check
        sub_level_forum.refresh_from_db()
        assert sub_level_forum.last_post_on == p2.created

    def test_can_reset_last_post_datetime_if_all_topics_have_been_deleted(self):
        # Setup
        sub_level_forum = create_forum(parent=self.top_level_forum)
        topic = create_topic(forum=sub_level_forum, poster=self.u1)
        PostFactory.create(topic=topic, poster=self.u1)
        # Run
        topic.delete()
        # Check
        sub_level_forum.refresh_from_db()
        assert sub_level_forum.last_post_on is None

    def test_can_send_a_specific_signal_when_a_forum_is_moved(self):
        # Setup
        topic = create_topic(forum=self.top_level_forum, poster=self.u1)
        PostFactory.create(topic=topic, poster=self.u1)
        PostFactory.create(topic=topic, poster=self.u1)
        # Run & check
        with mock_signal_receiver(forum_moved) as receiver:
            self.top_level_forum.parent = self.top_level_cat
            self.top_level_forum.save()
            assert receiver.call_count == 1

    def test_get_or_create(self):
        forum, created = Forum.objects.get_or_create(name="Test Forum", type=0)
        assert created is True
        assert isinstance(forum, Forum)
        assert forum.name == "Test Forum"


# Definition for a binary tree node.
from typing import List

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        if not inorder:
            return None

        root = TreeNode(preorder[0])

        rootPos = inorder.index(preorder[0])

        root.left = self.buildTree(preorder[1: 1 + rootPos], inorder[:rootPos])
        root.right = self.buildTree(preorder[rootPos + 1:], inorder[rootPos + 1:])

        return root

Arrays/105. 从前序与中序遍历序列构造二叉树.py

105. 从前序与中序遍历序列构造二叉树.py


# ===== SAMPLE
# player1pos = 4 - 1
# player2pos = 8 - 1
# ===== INPUT
player1pos = 4 - 1
player2pos = 6 - 1

board = range(0, 10) # easier, will add 1 to every score later

# ========================= STEP 1 ================================
def play(player1pos, player2pos):
    player1score = 0
    player2score = 0
    step = 0
    FINAL_SCORE = 1000
    while player1score < FINAL_SCORE and player2score < FINAL_SCORE:
        dice = 9*step + 6 # thanks oeis

        if step % 2 == 0: # if step is even, player 1 plays, otherwise player 2
            player1pos = board[ (player1pos + dice) % 10 ]
            player1score += player1pos+1
        else:
            player2pos = board[ (player2pos + dice) % 10 ]
            player2score += player2pos+1
        step += 1

    print(f'player1score: {player1score}, player2score: {player2score}, ðŸŽ²ï¸�: {dice}, step*3: {step*3}')
    print('Result:', min(player1score, player2score) * step*3)

# play(player1pos, player2pos)
# ========================= STEP 2 ================================

scoreCache = {}
def quantumPlay(player1pos, player2pos, player1score, player2score, step = 0):
    # print('  '*step, f'ðŸŽ²ï¸� PLAYER1 score {player1score}, pos {player1pos} / PLAYER2 score {player2score}, pos {player2pos}')
    FINAL_SCORE = 21 # or
    if player1score >= FINAL_SCORE:
        return (1, 0)
    elif player2score >= FINAL_SCORE:
        return (0, 1)
    elif (player1pos, player2pos, player1score, player2score) in scoreCache:
        return scoreCache[(player1pos, player2pos, player1score, player2score)]
    else:
        result = (0,0)
        for die1 in range(1,4): # split universes
            for die2 in range(1,4): # again!
                for die3 in range(1,4): # agaaain!
                    newPlayer1pos = (player1pos + die1 + die2 + die3) % 10
                    newPlayer1score = player1score + newPlayer1pos + 1
                    winning1, winning2 = quantumPlay(player2pos, newPlayer1pos, player2score, newPlayer1score, step+1)
                    result = (result[0]+winning2, result[1]+winning1)
        scoreCache[(player1pos, player2pos, player1score, player2score)] = result # store for next calls
        return result

game = quantumPlay(player1pos, player2pos, 0, 0)
print(game, max(game))


from django import forms
from django.contrib.auth.models import User

from .models import restaurant, Profile, Category, Product, companies, Order

# class RetaurantForm(forms.ModelForm):
#     class Meta:
#         model = restaurant
#         fields = ['name', 'image']

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class ProfileForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ('phone', 'job', 'is_rest_staff', 'is_comp_staff','company_id', 'restaurant_id')

class RestaurantForm(forms.ModelForm):
    class Meta:
        model = restaurant
        fields = ('name', 'address', 'phone', 'capacity', 'desc', 'logo')
        widgets = {
            'desc': forms.Textarea(attrs={'cols': 22, 'rows': 5}),
            # 'logo': PictureWidget
        }

class CategForm(forms.Form):
    name = forms.CharField(max_length=30)
    desc = forms.CharField(max_length=200,)

class CompanyForm(forms.ModelForm):
    class Meta:
        model = companies
        fields = ('name', 'address', 'phone', 'desc', 'logo')
        widgets = {
            'desc': forms.Textarea(attrs={'cols': 22, 'rows': 5}),
        }

class ProductForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = ('image', 'name', 'category_id','price', 'calories', 'fats','desc')
        widgets = {
            'desc': forms.Textarea(attrs={'cols': 22, 'rows': 5}),
        }

class OrderForm(forms.ModelForm):
    class Meta:
        model = Order
        fields = ( 'restaurant_id','product_id', 'qty')

    # name = forms.CharField(max_length=30)
    # category_id = forms.ModelMultipleChoiceField(queryset=Category.objects.all())


import numpy as np
import bcolz
import pickle

# Load GloVe word embeddings
words = []
idx = 0
word2idx = {}
glove_path = "data/embeddings/glove.6B"
vectors = bcolz.carray(np.zeros(1), rootdir = f"{glove_path}/6B.50.dat", mode = "w")
with open(f"{glove_path}/glove.6B.50d.txt", "rb") as f:
    for l in f:
        line = l.decode().split()
        word = line[0]
        words.append(word)
        word2idx[word] = idx
        idx += 1
        if idx % 10000 == 0:
            print("10,000 more done")
        vector = np.array(line[1 : ]).astype(np.float)
        vectors.append(vector)
vectors = bcolz.carray(vectors[1 : ].reshape((400000, 50)), rootdir = f"{glove_path}/6B.50.dat", mode = "w")
vectors.flush()
pickle.dump(words, open(f"{glove_path}/6B.50_words.pkl", "wb"))
pickle.dump(word2idx, open(f"{glove_path}/6B.50_idx.pkl", "wb"))


import django_filters
from .models import *

class ProductActualFilter(django_filters.FilterSet):
    """
        Фиильтр возвращающий товары с количеством больше 0
    """

    def actual_products(self, queryset, actual: bool):

        if actual == True:

            return queryset.filter(stock_balance__gt=0)
        else:
            return queryset

    class Meta:
        model = Product
        fields = ['stock_balance']

class WarehousFilterByList:
    """
        Фильтр возвращающий акктуальные товары в складском учете (модель динамическая, формируется в список)
    """

    def actual_warehous(self, data: list, actual: bool):
        print(actual)
        if actual == True:
            new_data = list()
            for value in data:
                if value['stock_balance'] is not None:
                    if value['stock_balance'] > 0:
                        new_data.append(value)
            return new_data
        else:
            return data


# faça um programa que leia o comprimento do
# cateto oposto e do cateto adjacente de um triangulo retangulo.
# calcule e mostre o comprimento da hiptenusa

#forma tradicional sem importação
catetoO = float(input('cateto oposto: '))
catetoA = float(input('cateto adjacente: '))
hipoenusa = (catetoO ** 2 + catetoA **2) **(1/2)
print('A hiptenusa vai medir {:.2f}'.format(hipoenusa))

#forma atraves do import expecifico
from math import hypot
catetoO = float(input('cateto oposto: '))
catetoA = float(input('cateto adjacente: '))
hipotenusa = hypot(catetoO, catetoA)
print('a hipoenusa vai medir {:.2f}'.format(hipotenusa))


import pandas as pd
import pickle

def load(path):
    """Load a SDV instance from a given path.
    Args:
        path (str):
            Path from which to load the SDV instance.
    """
    with open(path, 'rb') as f:
        model = pickle.load(f)

        return model

file_path = r"C:\Users\user\Documents\data_generation\program\\"
file_name = "testing_file.csv"
save_name = "testing_file_model.pkl"

data = load(file_path + save_name)

print(data)


#write a function that accepts a sentence as an argument
#and checks how many times a word appears in it.

# STEPS.
# 1. Split sentence into a list of words
# 2. create a placeholder to count the number of repetitions. Set it to 0
# 3. Iterate through the list of words
#       - check if the current item is equals to the word we're counting. If yes, increment count by 1. If not, ignore

love = "i love my cat Nala. Nala is a good kitty."

def word_count(sentence , word):
    word_list = sentence.split(" ")
    count = 0

    for item in word_list:
        if item.lower() == word.lower():
            count += 1
    return count

print(word_count(love , "nala"))


# 동전

# 금액의 오름차순으로 정렬된 동전들을 차례대로 사용할 때
# 이전에 계산된 각 금액에 대한 경우의 수는 누적해서 갱신되므로
# dp를 1차원 리스트로 선언해서
# 현재 순회중인 동전을 이용한 경우의 수를 매 순회마다 누적한다면
# 결국 주어진 금액을 만들기 위한 경우의 수를 구할 수 있음

import sys

def main():
    input = sys.stdin.readline
    print = sys.stdout.write

    tc = int(input().rstrip())
    while tc > 0:
        n = int(input().rstrip())
        tmp = list(map(int, input().split()))
        m = int(input().rstrip())

        dp = [0] * (m+1)
        dp[0] = 1

        for t in tmp:
            for j in range(t, m+1):
                dp[j] += dp[j-t]

        print(f"{dp[m]}\n")
        tc -= 1

main()


from tkinter import *
from tkinter import ttk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
import numpy as np
import warnings
warnings.filterwarnings("ignore", category=np.VisibleDeprecationWarning)
import sys
import math
import time
import os
import numpy as np
import matplotlib.pyplot as plt
from functions_v6 import calculate_optimized_alphas, get_stress_points_in_Yieldlocus, get_R_vs_Theta_Rb_values

class widgets(Frame):

    def __init__(self, window, picks=[]):

      Frame.__init__(self, window)

      self.inputs = []
      self.stress_and_R = ['S45','S90','Sbiax','R00','R45','R90','Rbiax', 'e']
      lf = LabelFrame(window, text='Inputs')
      lf.grid(column=0, row=0)
      value_picks = [[0.85, 1.15, 2], [6,8,2]]

      label = Label(lf, text='S00', width=6)
      label.grid(row=0, column=0)
      var = IntVar()
      var.set(1)
      self.S00 = Entry(lf, textvariable=var, width=6)
      self.S00.grid(row=0, column=1)

      for j, para in enumerate(self.stress_and_R):
          label = Label(lf, text=self.stress_and_R[j], width=8)
          label.grid(row=0, column=j+3)

          stress_and_R_range  = []
          for i in range(len(picks)):

              label = Label(lf, text=picks[i], width=6)
              label.grid(row=i+1, column=2)

              var = IntVar()
              if para== 'e':
                  var.set(value_picks[1][i])
              else:
                  var.set(value_picks[0][i])

              ent = Entry(lf, textvariable=var, width=8)
              ent.grid(row=i+1, column=j+3)

              stress_and_R_range.append(ent)

          self.inputs.append(stress_and_R_range)

          Button(lf, text='Get the plot!', command=allstates).grid(row=12,column=1)

    def state(self):

      S00 = float(self.S00.get())
      #e_min = float(self.e_min.get())
      #e_max = float(self.e_max.get())
      #exponent_values = [float(self.e_min.get()), float(self.e_max.get())]

      input_data = []
      for i, stress_and_R_input in enumerate(self.inputs):
          #alpha_values_list = []
          stress_and_R_input = list(map((lambda ent: float(ent.get())), stress_and_R_input))
          #print(alpha_input)
          n_step = stress_and_R_input[-1]
          stress_and_R_values = stress_and_R_input[:-1]

          step = (stress_and_R_values[1]-stress_and_R_values[0]) / (n_step - 1)
          #print(step_alpha)
          if n_step > 2:
              for j in range(int(n_step-2)): # 2 accounting for the first and the last points
                stress_and_R_values = np.insert(stress_and_R_values, j+1, stress_and_R_values[j]+step, axis=0)

          input_data.append(stress_and_R_values)

      return input_data, S00, n_step

def allstates():

    global count, canvas, fig, ax1, ax2, ax3, toolbar

    count +=1

    if count != 1:
        ax1.cla()
        ax2.cla()
        ax3.cla()
        ax4.cla()
        ax5.cla()
        ax6.cla()
        ax7.cla()
        ax8.cla()

    input_data, S00, n_step = lng.state()

    print(np.shape(input_data))
    print(input_data)

    no_of_calcns = int(n_step)**8
    alpha1_values = np.zeros(no_of_calcns).tolist()  # or use [0] * inputs[4]**8   OR use numpy arrays (faster and smaller in size)
    alpha2_values = np.zeros(no_of_calcns).tolist()
    alpha3_values = np.zeros(no_of_calcns).tolist()
    alpha4_values = np.zeros(no_of_calcns).tolist()
    alpha5_values = np.zeros(no_of_calcns).tolist()
    alpha6_values = np.zeros(no_of_calcns).tolist()
    alpha7_values = np.zeros(no_of_calcns).tolist()
    alpha8_values = np.zeros(no_of_calcns).tolist()

    no_of_calcns = 0
    track_calcn_no = []
    for a in input_data[7]: # this is the exponent of the yield locus
        for S45 in input_data[0]:
            for S90 in input_data[1]:
                for Sbiax in input_data[2]:
                    for R00 in input_data[3]:
                        for R45 in input_data[4]:
                            for R90 in input_data[5]:
                                for Rbiax in input_data[6]:

                                    alpha = calculate_optimized_alphas(a,S00,S45,S90,Sbiax,R00,R45,R90,Rbiax)

                                    S = get_stress_points_in_Yieldlocus(alpha,a,shear=0)
                                    R,Rb = get_R_vs_Theta_Rb_values(alpha,a)

                                    given_stress = np.array([[S00, S45, S90, Sbiax]])
                                    given_R = np.array([[R00, R45, R90, Rbiax]])

                                    calculated_stress = np.array([[S[0][2], S[0][4], S[0][3], S[0][5]]])
                                    calculated_R = np.array([[R[0][0], R[0][45], R[0][90], Rb[0]]])

                                    Absolute_Error_for_stress = (abs(given_stress - calculated_stress))
                                    Absolute_Error_for_R_value = (abs(given_R - calculated_R))
                                    # the lines below perform element by element division, / is a shorthand for numpy.divide
                                    Percentage_Error_for_stress = (abs(given_stress - calculated_stress) / given_stress)*100.0
                                    Percentage_Error_for_R_value = (abs(given_R - calculated_R) / given_R)*100.0

                                    alpha1_values[no_of_calcns] = alpha[0]
                                    alpha2_values[no_of_calcns] = alpha[1]
                                    alpha3_values[no_of_calcns] = alpha[2]
                                    alpha4_values[no_of_calcns] = alpha[3]
                                    alpha5_values[no_of_calcns] = alpha[4]
                                    alpha6_values[no_of_calcns] = alpha[5]
                                    alpha7_values[no_of_calcns] = alpha[6]
                                    alpha8_values[no_of_calcns] = alpha[7]

                                    for (pe_stress, pe_R) in zip(Percentage_Error_for_stress[0], Percentage_Error_for_R_value[0]):
                                        if (pe_stress > 1) or (pe_R > 1):
                                            track_calcn_no.append(no_of_calcns)
                                            break
                                            # if no_of_calcns not in track_calcn_no:
                                            #     track_calcn_no.append(no_of_calcns)

                                    no_of_calcns += 1

                                    #break

    x = list(range(no_of_calcns))
    print("total number of simulations:", no_of_calcns)

    min_alpha1, max_alpha1 = min(alpha1_values), max(alpha1_values)
    min_alpha2, max_alpha2 = min(alpha2_values), max(alpha2_values)
    min_alpha3, max_alpha3 = min(alpha3_values), max(alpha3_values)
    min_alpha4, max_alpha4 = min(alpha4_values), max(alpha4_values)
    min_alpha5, max_alpha5 = min(alpha5_values), max(alpha5_values)
    min_alpha6, max_alpha6 = min(alpha6_values), max(alpha6_values)
    min_alpha7, max_alpha7 = min(alpha7_values), max(alpha7_values)
    min_alpha8, max_alpha8 = min(alpha8_values), max(alpha8_values)

    print("red points:", track_calcn_no)

    for idx in x:
        if idx in track_calcn_no:
            ax1.scatter(idx, alpha1_values[idx], color='red', s=10)
            ax2.scatter(idx, alpha2_values[idx], color='red', s=10)
            ax3.scatter(idx, alpha3_values[idx], color='red', s=10)
            ax4.scatter(idx, alpha4_values[idx], color='red', s=10)
            ax5.scatter(idx, alpha5_values[idx], color='red', s=10)
            ax6.scatter(idx, alpha6_values[idx], color='red', s=10)
            ax7.scatter(idx, alpha7_values[idx], color='red', s=10)
            ax8.scatter(idx, alpha8_values[idx], color='red', s=10)

        else:
            ax1.scatter(idx, alpha1_values[idx], color='green', s=10)
            ax2.scatter(idx, alpha2_values[idx], color='green', s=10)
            ax3.scatter(idx, alpha3_values[idx], color='green', s=10)
            ax4.scatter(idx, alpha4_values[idx], color='green', s=10)
            ax5.scatter(idx, alpha5_values[idx], color='green', s=10)
            ax6.scatter(idx, alpha6_values[idx], color='green', s=10)
            ax7.scatter(idx, alpha7_values[idx], color='green', s=10)
            ax8.scatter(idx, alpha8_values[idx], color='green', s=10)

    ax1.set_ylabel('alpha1', fontweight='bold')
    ax1.set_xlabel('no. of calculations', fontweight='bold')
    ax2.set_ylabel('alpha2', fontweight='bold')
    ax2.set_xlabel('no. of calculations', fontweight='bold')
    ax3.set_ylabel('alpha3', fontweight='bold')
    ax3.set_xlabel('no. of calculations', fontweight='bold')
    ax4.set_ylabel('alpha4', fontweight='bold')
    ax4.set_xlabel('no. of calculations', fontweight='bold')
    ax5.set_ylabel('alpha5', fontweight='bold')
    ax5.set_xlabel('no. of calculations', fontweight='bold')
    ax6.set_ylabel('alpha6', fontweight='bold')
    ax6.set_xlabel('no. of calculations', fontweight='bold')
    ax7.set_ylabel('alpha7', fontweight='bold')
    ax7.set_xlabel('no. of calculations', fontweight='bold')
    ax8.set_ylabel('alpha8', fontweight='bold')
    ax8.set_xlabel('no. of calculations', fontweight='bold')

    ax1.axhline(y=max_alpha1, color='red', label=f'max={max_alpha1}')
    ax1.axhline(y=min_alpha1, color='green', label=f'min={min_alpha1}')
    ax1.legend(loc='upper right')
    ax2.axhline(y=max_alpha2, color='red', label=f'max={max_alpha2}')
    ax2.axhline(y=min_alpha2, color='green', label=f'min={min_alpha2}')
    ax2.legend(loc='upper right')
    ax3.axhline(y=max_alpha3, color='red', label=f'max={max_alpha3}')
    ax3.axhline(y=min_alpha3, color='green', label=f'min={min_alpha3}')
    ax3.legend(loc='upper right')
    ax4.axhline(y=max_alpha4, color='red', label=f'max={max_alpha4}')
    ax4.axhline(y=min_alpha4, color='green', label=f'min={min_alpha4}')
    ax4.legend(loc='upper right')
    ax5.axhline(y=max_alpha5, color='red', label=f'max={max_alpha5}')
    ax5.axhline(y=min_alpha5, color='green', label=f'min={min_alpha5}')
    ax5.legend(loc='upper right')
    ax6.axhline(y=max_alpha6, color='red', label=f'max={max_alpha6}')
    ax6.axhline(y=min_alpha6, color='green', label=f'min={min_alpha6}')
    ax6.legend(loc='upper right')
    ax7.axhline(y=max_alpha7, color='red', label=f'max={max_alpha7}')
    ax7.axhline(y=min_alpha7, color='green', label=f'min={min_alpha7}')
    ax7.legend(loc='upper right')
    ax8.axhline(y=max_alpha8, color='red', label=f'max={max_alpha8}')
    ax8.axhline(y=min_alpha8, color='green', label=f'min={min_alpha8}')
    ax8.legend(loc='upper right')

    #ax1.tick_params(axis='both')
    #ax2.tick_params(axis='both')
    #ax3.tick_params(axis='both')

    canvas.draw()
    canvas.get_tk_widget().grid(row = 10, column=0)

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

    alpha1_values.clear()
    alpha2_values.clear()
    alpha3_values.clear()
    alpha4_values.clear()
    alpha5_values.clear()
    alpha6_values.clear()
    alpha7_values.clear()
    alpha8_values.clear()

    print('plotted!')

    end_time = time.time()
    total_time = (end_time - start_time)/60
    print(f'Total Time: {(total_time):.4f} mins')

if __name__ == '__main__':

    root = Tk()
    root.title('Reverse  Computation')
    root.geometry("1280x800")

    start_time = time.time()

    count = 0

    content = ttk.Frame(root)
    frame1 = ttk.Frame(content, borderwidth=5, relief="ridge")
    frame3 = ttk.Frame(content, borderwidth=5, relief="ridge")
    #width and height here sets the dimension of the frame , width=1250, height=550
    content.grid(column=0, row=0)

    frame1.grid(column=0, row=0)
    frame3.grid(column=0, row=10, columnspan=70, rowspan=70)

    fig = plt.figure()
    fig.set_figheight(8) #sets the height and width of the white space inside frame3
    fig.set_figwidth(18)

    ax1 = plt.subplot2grid(shape=(2,4), loc=(0, 0), rowspan = 1, colspan = 1) #shape=Shape of grid in which to place axis
    ax2 = plt.subplot2grid(shape=(2,4), loc=(0, 1), rowspan = 1, colspan = 1)
    ax3 = plt.subplot2grid(shape=(2,4), loc=(0, 2), rowspan = 1, colspan = 1)
    ax4 = plt.subplot2grid(shape=(2,4), loc=(0, 3), rowspan = 1, colspan = 1)
    ax5 = plt.subplot2grid(shape=(2,4), loc=(1, 0), rowspan = 1, colspan = 1)
    ax6 = plt.subplot2grid(shape=(2,4), loc=(1, 1), rowspan = 1, colspan = 1)
    ax7 = plt.subplot2grid(shape=(2,4), loc=(1, 2), rowspan = 1, colspan = 1)
    ax8 = plt.subplot2grid(shape=(2,4), loc=(1, 3), rowspan = 1, colspan = 1)

    #fig.tight_layout()

    canvas = FigureCanvasTkAgg(fig, master = frame3)

    toolbarFrame = Frame(master=frame1)
    toolbarFrame.grid(row=25,column=0)
    toolbar = NavigationToolbar2Tk(canvas, toolbarFrame)

    lng = widgets(frame1, ['min', 'max', 'NPoints'])

    root.mainloop()


def deepcopy(x, visited):
    # "id(variable)"" to get address
    # "type(variable) is list" to check if a variable is a list
    x_deepcopy = list()
    visited[id(x)] = x_deepcopy
    copied_id = dict()
    print(id(x))
    for a in range(len(x)):
        i = x[a]
        if type(i) == list:
            if visited.get(id(i), None) == None:
                i_deepcopy = deepcopy(i, visited)
                x_deepcopy.append(i_deepcopy)
            else:
                x_deepcopy.append(visited[id(i)])
        else:
            x_deepcopy.append(i)
    return x_deepcopy

def testDeepcopy(x):
    visited = dict()
    x_deepcopy = deepcopy(x, visited)
    for i,j in zip(x, x_deepcopy):
        if(type(i) is list):
            assert(id(i) != id(j))
    #assert(x == x_deepcopy)
    print(x)
    print(x_deepcopy)

# testDeepcopy([1, 2, 3, 4, 5])
# testDeepcopy([1, 2, [3, 4], 5])
# testDeepcopy([1, [2, [3, [4, [5]]]]])
# testDeepcopy([[1,[2],[3, 4],[[[5]]]]])
# x = [1, 2, 3]
# y = x
# x.append(y)
# testDeepcopy(x)

x = [[1,5]]
y = [2,x]
z = [3,y]
w = [4,z]
x.append(w)
testDeepcopy(x)


# Crie um programa que tenha uma tupla com várias palavras(não usar acentos). Depois disso, você deve mostrar, pra cada
# palavra, quais são as suas vogais.

lista = ('Vinicius', 'Gabryel', 'Dhiego', 'Alice', 'Luana', 'Alanis', 'Pedro')

for palavra in lista:
    print(f'\n"{palavra}" tem as vogais ', end='')
    for letra in palavra:
        if letra.lower() in 'aeiou':
            print(letra, end=', ')


import sys
input = sys.stdin.readline

n = int(input())
arr = [list(map(int, input().split())) for _ in range(n)]
arr.sort(key=lambda x:(-x[0], -x[1]))

maxDate = arr[0][0]
temp = [[] for _ in range(maxDate)]
result = 0

for i in range(maxDate):
    for d, w in arr:
        if d >= i + 1:
            temp[i].append(w)

for i in range(maxDate - 1, -1, -1):
    if temp[i]:
        m = max(temp[i])
        result += m
        for j in temp:
            if m in j:
                j.remove(m)

print(result)


'''
DESCRIPTION
----------

Plotting script to make the skymap figure of the proposal. (Where are the
clusters on the sky?)

'''

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

from astropy.table import Table
from astropy.io import ascii
from astropy.coordinates import SkyCoord
import astropy.units as u

from math import pi
import pickle, os

from scipy.interpolate import interp1d

global COLORS
COLORS = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b',
          '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']

# cite:
#
# Jaffe, T. J. & Barclay, T. 2017, ticgen: A tool for calculating a TESS
# magnitude, and an expected noise level for stars to be observed by TESS.,
# v1.0.0, Zenodo, doi:10.5281/zenodo.888217
#
# and Stassun & friends (2017).
#import ticgen as ticgen

# # These two, from the website
# # http://dc.zah.uni-heidelberg.de/mwsc/q/clu/form
# # are actually outdated or something. They provided too few resuls..
# close_certain = pd.read_csv('../data/MWSC_search_lt_2000_pc_type_certain.csv')
# close_junk = pd.read_csv('../data/MWSC_search_lt_2000_pc_type_certain.csv')

def get_cluster_data():

    # Downloaded the MWSC from
    # http://cdsarc.u-strasbg.fr/viz-bin/Cat?cat=J%2FA%2BA%2F558%2FA53&target=http&
    tab = Table.read('../data/Kharchenko_2013_MWSC.vot', format='votable')

    df = tab.to_pandas()

    for colname in ['Type', 'Name', 'n_Type', 'SType']:
        df[colname] = [e.decode('utf-8') for e in list(df[colname])]

    # From erratum:
    # For the Sun-like star, a 4 Re planet produces a transit depth of 0.13%. The
    # limiting magnitude for transits to be detectable is about I_C = 11.4 . This
    # also corresponds to K_s ~= 10.6 and a maximum distance of 290 pc, assuming no
    # extinction.

    cinds = np.array(df['d']<500)
    close = df[cinds]
    finds = np.array(df['d']<1000)
    far = df[finds]

    N_c_r0 = int(np.sum(close['N1sr0']))
    N_c_r1 = int(np.sum(close['N1sr1']))
    N_c_r2 = int(np.sum(close['N1sr2']))
    N_f_r0 = int(np.sum(far['N1sr0']))
    N_f_r1 = int(np.sum(far['N1sr1']))
    N_f_r2 = int(np.sum(far['N1sr2']))

    type_d = {'a':'association', 'g':'globular cluster', 'm':'moving group',
              'n':'nebulosity/presence of nebulosity', 'r':'remnant cluster',
              's':'asterism', '': 'no label'}

    ntype_d = {'o':'object','c':'candidate','':'no label'}

    print('*'*50)
    print('\nMilky Way Star Clusters (close := <500pc)'
          '\nN_clusters: {:d}'.format(len(close))+\
          '\nN_stars (in core): {:d}'.format(N_c_r0)+\
          '\nN_stars (in central part): {:d}'.format(N_c_r1)+\
          '\nN_stars (in cluster): {:d}'.format(N_c_r2))

    print('\n'+'*'*50)
    print('\nMilky Way Star Clusters (far := <1000pc)'
          '\nN_clusters: {:d}'.format(len(far))+\
          '\nN_stars (in core): {:d}'.format(N_f_r0)+\
          '\nN_stars (in central part): {:d}'.format(N_f_r1)+\
          '\nN_stars (in cluster): {:d}'.format(N_f_r2))

    print('\n'+'*'*50)

    ####################
    # Post-processing. #
    ####################
    # Compute mean density
    mean_N_star_per_sqdeg = df['N1sr2'] / (pi * df['r2']**2)
    df['mean_N_star_per_sqdeg'] = mean_N_star_per_sqdeg

    # # Compute King profiles
    # king_profiles, theta_profiles = [], []
    # for rt, rc, k, d in zip(np.array(df['rt']),
    #                         np.array(df['rc']),
    #                         np.array(df['k']),
    #                         np.array(df['d'])):

    #     sigma, theta = get_king_proj_density_profile(rt, rc, k, d)
    #     king_profiles.append(sigma)
    #     theta_profiles.append(theta)

    # df['king_profile'] = king_profiles
    # df['theta'] = theta_profiles

    ra = np.array(df['RAJ2000'])
    dec = np.array(df['DEJ2000'])

    c = SkyCoord(ra=ra*u.degree, dec=dec*u.degree, frame='icrs')

    galactic_long = np.array(c.galactic.l)
    galactic_lat = np.array(c.galactic.b)
    ecliptic_long = np.array(c.barycentrictrueecliptic.lon)
    ecliptic_lat = np.array(c.barycentrictrueecliptic.lat)

    df['galactic_long'] = galactic_long
    df['galactic_lat'] = galactic_lat
    df['ecliptic_long'] = ecliptic_long
    df['ecliptic_lat'] = ecliptic_lat

    cinds = np.array(df['d']<500)
    close = df[cinds]
    finds = np.array(df['d']<1000)
    far = df[finds]

    return close, far, df

def make_wget_script(df):
    '''
    to download stellar data for each cluster, need to run a script of wgets.
    this function makes the script.
    '''

    # get MWSC ids in "0012", "0007" format
    mwsc = np.array(df['MWSC'])
    mwsc_ids = np.array([str(int(f)).zfill(4) for f in mwsc])

    names = np.array(df['Name'])

    f = open('../data/MWSC_stellar_data/get_stellar_data.sh', 'w')

    outstrs = []
    for mwsc_id, name in zip(mwsc_ids, names):
        startstr = 'wget '+\
                 'ftp://cdsarc.u-strasbg.fr/pub/cats/J/A%2BA/558/A53/stars/2m_'
        middlestr = str(mwsc_id) + '_' + str(name)
        endstr = '.dat.bz2 ;\n'
        outstr = startstr + middlestr + endstr
        outstrs.append(outstr)

    f.writelines(outstrs)
    f.close()

    print('made wget script!')

def plot_cluster_positions_scicase(df):
    '''
    Show the positions of d<2kpc clusters, and highlight those with rotation
    period measurements & transiting planets.
    '''

    rotn_clusters = ['NGC_1976', # AKA the orion nebula cluster
                     'NGC_6530',
                     'NGC_2264',
                     'Cep_OB3',
                     'NGC_2362',
                     'NGC_869', # h Per, one of the double cluster
                     'NGC_2547',
                     'IC_2391',
                     'Melotte_20', # alpha Persei cluster, alpha Per
                     'Melotte_22', # AKA Pleiades
                     'NGC_2323', # M 50
                     'NGC_2168', #M 35
                     'NGC_2516',
                     'NGC_1039', #M 34
                     'NGC_2099', # M 37
                     #'NGC_2632', #Praesepe, comment out to avoid overlap
                     #'NGC_6811', #comment out to avoid overlap
                     'NGC_2682' ] #M 67

    transiting_planet_clusters = [
                     'NGC_6811',
                     'NGC_2632' #Praesepe
                    ]

    df = df[df['d'] < 2000]

    df_rotn = df.loc[df['Name'].isin(rotn_clusters)]
    df_rotn = df_rotn[
            ['ecliptic_lat','ecliptic_long','galactic_lat','galactic_long',
            'Name']
            ]

    df_tra = df.loc[df['Name'].isin(transiting_planet_clusters)]

    # Above rotation lists were from Table 1 of Gallet & Bouvier 2015,
    # including M67 which was observed by K2.  Transiting planets from the few
    # papers that have them.  They are cross-matching MWSC's naming scheme. I
    # could not find the Hyades or ScoCen OB.  They both have transiting
    # planets, and the former has rotation studies done.

    c_Hyades = SkyCoord(ra='4h27m', dec=15*u.degree + 52*u.arcminute)
    df_hyades = pd.DataFrame({
            'Name':'Hyades',
            'ecliptic_long':float(c_Hyades.barycentrictrueecliptic.lon.value),
            'ecliptic_lat':float(c_Hyades.barycentrictrueecliptic.lat.value),
            'galactic_long':float(c_Hyades.galactic.l.value),
            'galactic_lat':float(c_Hyades.galactic.b.value)}, index=[0])

    c_ScoOB2 = SkyCoord(ra='16h10m14.73s', dec='-19d19m09.38s') # Mann+2016's position
    df_ScoOB2 = pd.DataFrame({
            'Name':'Sco_OB2',
            'ecliptic_long':float(c_ScoOB2.barycentrictrueecliptic.lon.value),
            'ecliptic_lat':float(c_ScoOB2.barycentrictrueecliptic.lat.value),
            'galactic_long':float(c_ScoOB2.galactic.l.value),
            'galactic_lat':float(c_ScoOB2.galactic.b.value)}, index=[0])

    df_tra = df_tra.append(df_hyades, ignore_index=True)
    df_tra = df_tra.append(df_ScoOB2, ignore_index=True)
    #df_rotn = df_rotn.append(df_hyades, ignore_index=True) #avoid overlap

    # End of data wrangling.

    import matplotlib as mpl
    from mpl_toolkits.basemap import Basemap

    for coord in ['galactic','ecliptic']:

        plt.close('all')
        #f, ax = plt.subplots(figsize=(4,4))
        f = plt.figure(figsize=(0.7*5,0.7*4))
        ax = plt.gca()
        m = Basemap(projection='kav7',lon_0=0, resolution='c', ax=ax)

        lats = np.array(df[coord+'_lat'])
        lons = np.array(df[coord+'_long'])
        x, y = m(lons, lats)
        m.scatter(x,y,2,marker='o',facecolor=COLORS[0], zorder=4,
                alpha=0.9,edgecolors=COLORS[0], lw=0)

        lats = np.array(df_rotn[coord+'_lat'])
        lons = np.array(df_rotn[coord+'_long'])
        x, y = m(lons, lats)
        m.scatter(x,y,42,marker='*',color=COLORS[1],edgecolors='k',
                label='have rotation studies', zorder=5,lw=0.4)

        lats = np.array(df_tra[coord+'_lat'])
        lons = np.array(df_tra[coord+'_long'])
        x, y = m(lons, lats)
        m.scatter(x,y,13,marker='s',color=COLORS[1],edgecolors='k',
                label='also have transiting planets', zorder=6, lw=0.45)

        parallels = np.arange(-90.,120.,30.)
        meridians = np.arange(0.,420.,60.)
	# labels = [left,right,top,bottom]
        ps = m.drawparallels(parallels, labels=[1,0,0,0], zorder=2,
                fontsize='x-small')
        ms = m.drawmeridians(meridians, labels=[0,0,0,1], zorder=2,
                fontsize='x-small')

        # Shrink current axis's height by 10% on the bottom
        box = ax.get_position()
        ax.set_position([box.x0, box.y0 + box.height * 0.1,
            box.width, box.height * 0.9])

	# Put a legend below current axis
        #ax.legend(loc='upper center', bbox_to_anchor=(0.01, 0.02),
        #        fancybox=True, ncol=1, fontsize='x-small')

        for _m in ms:
            try:
                #ms[_m][1][0].set_rotation(45)
                if '60' in ms[_m][1][0].get_text():
                    ms[_m][1][0].set_text('')
            except:
                pass
        for _p in ps:
            try:
                if '30' in ps[_p][1][0].get_text():
                    ps[_p][1][0].set_text('')
            except:
                pass

        ax.set_xlabel(coord+' long', labelpad=13, fontsize='x-small')
        ax.set_ylabel(coord+' lat', labelpad=13, fontsize='x-small')

        ######################
	# add TESS footprint #
        ######################
        dat = np.genfromtxt('../data/shemi_nhemi.csv', delimiter=',')
        dat = pd.DataFrame(np.transpose(dat), columns=['icSys', 'tSys', 'teff',
            'logg', 'r', 'm', 'eLat', 'eLon', 'micSys', 'mvSys', 'mic', 'mv',
            'stat', 'nPntg'])
        eLon, eLat = np.array(dat.eLon), np.array(dat.eLat)
        nPntg = np.array(dat.nPntg)
        if coord=='galactic':
            c = SkyCoord(lat=eLat*u.degree, lon=eLon*u.degree,
                    frame='barycentrictrueecliptic')
            lon = np.array(c.galactic.l)
            lat = np.array(c.galactic.b)

        elif coord=='ecliptic':
            lon, lat = eLon, eLat

        nPntg[nPntg >= 4] = 4

        ncolor = 4
        cmap1 = mpl.colors.ListedColormap(
                sns.color_palette("Greys", n_colors=ncolor, desat=1))
        bounds= list(np.arange(0.5,ncolor+1,1))
        norm1 = mpl.colors.BoundaryNorm(bounds, cmap1.N)

        x, y = m(lon, lat)
        out = m.scatter(x,y,s=0.2,marker='s',c=nPntg, zorder=1, cmap=cmap1,
                norm=norm1, rasterized=True, alpha=0.5)
        out = m.scatter(x,y,s=0, marker='s',c=nPntg, zorder=-1, cmap=cmap1,
                norm=norm1, rasterized=True, alpha=1)
        m.drawmapboundary()
        #cbar = f.colorbar(out, cmap=cmap1, norm=norm1, boundaries=bounds,
        #    fraction=0.025, pad=0.05, ticks=np.arange(ncolor)+1,
        #    orientation='vertical')

        #ylabels = np.arange(1,ncolor+1,1)
        #cbarlabels = list(map(str, ylabels))[:-1]
        #cbarlabels.append('$\geq\! 4$')
        #cbar.ax.set_yticklabels(cbarlabels, fontsize='x-small')
        #cbar.set_label('N pointings', rotation=270, labelpad=5, fontsize='x-small')
        ####################
        f.tight_layout()

        f.savefig('cluster_positions_'+coord+'_scicase.pdf', bbox_inches='tight')

if __name__ == '__main__':

    #make_wget_script(df)

    close, far, df = get_cluster_data()

    plot_cluster_positions_scicase(df)


# Reading from TEXT FILES

with open('welcome.txt') as text_file:
  text_data = text_file.read()                      # read() method Reads the content of the file
  print(text_data)

with open('how_many_lines.txt') as lines_doc:
  lines = lines_doc.readlines()                     # readLines() method fetches all the lines of the file in a list through which we can iterate
  print(lines)
  for line in lines:
    print(line)

with open('millay_sonnet.txt') as sonnet_doc:       #readline() method reads a single line from the file
  first_line = sonnet_doc.readline()
  second_line = sonnet_doc.readline()
  print(second_line)

# writing and appending to TEXT FILES
with open('generated_file.txt', 'w') as gen_file:
  gen_file.write("What an incredible file!")

with open('generated_file.txt', 'a') as gen_file:
  gen_file.write("... and it still is")

# Reading from CSV FILES
import csv
with open('cool_csv.csv') as cool_csv_file:
  cool_csv_dict = csv.DictReader(cool_csv_file)
  for row in cool_csv_dict:
    print(row)

#writing to CSV FILES
big_list = [{'name': 'James Willo', 'userid': 3242, 'is_admin': False},
            {'name': 'Robert Henry', 'userid': 2525942, 'is_admin': False},
            {'name': 'Henry Gale', 'userid': 15890235, 'is_admin': False},
            {'name': 'Dendris Stulo', 'userid': 572189563, 'is_admin': True}]

import csv

with open('output.csv', 'w') as output_csv:
  fields = ['name', 'userid', 'is_admin']
  output_writer = csv.DictWriter(output_csv, fieldnames=fields)

  output_writer.writeheader()
  for item in big_list:
    output_writer.writerow(item)

# Reading from JSON FILE
import json

with open('purchase_14781239.json') as purchase_json:
  purchase_data = json.load(purchase_json)

print(purchase_data['user'])

#writing to JSON FILE

origin_json = {
  'eventId': 674189,
  'dateTime': '2015-02-12T09:23:17.511Z',
  'chocolate': 'Semi-sweet Dark',
  'isTomatoAFruit': True
}

import json

with open('output.json', 'w') as target_json_file:
  json.dump(origin_json, target_json_file)


#!/usr/bin/env python3

import sys

import pygame
from settings import Settings

def drawStuff(background):
	pygame.draw.line(background, (255, 0, 0), (100,300), (1100, 300))

def run_game():
	#定义运行函数并初始化屏幕对象
	pygame.init()#初始化
	ai_settings = Settings()#实例化对象
	screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))#调用对象的参数
	pygame.display.set_caption("Invasion")#标题

	while True:#主循环
		# 观察输入指令
		for event in pygame.event.get():#退出循环
			if event.type == pygame.QUIT:
				sys.exit()

		screen.fill(ai_settings.bg_color)#1重绘屏幕

		pygame.display.flip()#2使屏幕可见

run_game()


from pymongo import ReturnDocument
from telegram import ReplyKeyboardMarkup
from telegram import ReplyKeyboardRemove
from telegram import Update
from telegram.ext import CallbackContext
from telegram.ext import ConversationHandler

from thx_bot.commands import CHOOSING_REWARDS
from thx_bot.commands import TYPING_REWARD_REPLY
from thx_bot.models.channels import Channel
from thx_bot.services.thx_api_client import get_asset_pool_info
from thx_bot.services.thx_api_client import get_pool_rewards
from thx_bot.validators import only_chat_admin
from thx_bot.validators import only_if_channel_configured
from thx_bot.validators import only_in_private_chat

OPTION_SHOW_REWARDS = "Show rewards"
OPTION_SET_REWARD = "Set Reward"
REPLY_KEYBOARD = [
    [OPTION_SET_REWARD],
    ["Done", OPTION_SHOW_REWARDS],
]
REPLY_OPTION_TO_DB_KEY = {
    OPTION_SET_REWARD.lower(): "reward",
}
MARKUP = ReplyKeyboardMarkup(REPLY_KEYBOARD, one_time_keyboard=True)

@only_if_channel_configured
@only_chat_admin
@only_in_private_chat
def rewards_entrypoint(update: Update, context: CallbackContext) -> int:
    reply_text = "💰 Please, select reward for the channel, " \
                 "so your chat users can start getting rewards"
    update.message.reply_text(reply_text, reply_markup=MARKUP)

    return CHOOSING_REWARDS

@only_if_channel_configured
@only_chat_admin
@only_in_private_chat
def regular_choice_reward(update: Update, context: CallbackContext) -> int:
    text = update.message.text.lower()
    if text not in REPLY_OPTION_TO_DB_KEY.keys():
        update.message.reply_text("Unknown choice. Please, click on inline buttons with choices")
        return ConversationHandler.END
    text = update.message.text.lower()
    context.user_data['choice'] = text
    reply_text = "Please, specify reward ID that will be used for you chat:"
    update.message.reply_text(reply_text)

    return TYPING_REWARD_REPLY

@only_chat_admin
@only_in_private_chat
@only_if_channel_configured
def received_information_reward(update: Update, context: CallbackContext) -> int:
    try:
        text = int(update.message.text)
    except ValueError:
        update.message.reply_text(
            "Please, specify valid reward id",
            reply_markup=MARKUP,
        )
        return CHOOSING_REWARDS
    category = context.user_data['choice']
    context.user_data[category] = text
    del context.user_data['choice']

    channel = Channel.collection.find_one_and_update(
        {'channel_id': context.user_data['channel_id']},
        {'$set': {REPLY_OPTION_TO_DB_KEY[category]: text}},
        return_document=ReturnDocument.AFTER
    )
    update.message.reply_text(
        "Cool! Your reward id for the channel is:"
        f"{channel.get(f'{REPLY_OPTION_TO_DB_KEY[category]}')}",
        reply_markup=MARKUP,
    )

    return CHOOSING_REWARDS

@only_chat_admin
@only_in_private_chat
@only_if_channel_configured
def done_rewards(update: Update, context: CallbackContext) -> int:
    if 'choice' in context.user_data:
        del context.user_data['choice']

    channel = Channel(Channel.collection.find_one({'channel_id': context.user_data['channel_id']}))
    reply = "Please, specify valid reward ID so users can start claiming rewards!"
    if getattr(channel, "reward"):
        status, __ = get_pool_rewards(channel, channel.reward)
        if status == 200:
            reply = f"You have set reward with ID {channel.reward} your channel. " \
                    f"User in your channel now can receive rewards!"
    update.message.reply_text(
        reply,
        reply_markup=ReplyKeyboardRemove(),
    )
    return ConversationHandler.END

@only_if_channel_configured
@only_chat_admin
@only_in_private_chat
def pool_show_rewards_command(update: Update, context: CallbackContext) -> None:
    channel = Channel(
        Channel.collection.find_one({'channel_id': context.user_data.get('channel_id')})
    )
    status, rewards_response = get_pool_rewards(channel)
    pool_status, pool_info = get_asset_pool_info(channel)

    if status != 200 or pool_status != 200:
        update.message.reply_text("Your pool is not configured or pool has no rewards")
        return ConversationHandler.END

    rewards = ""
    token = pool_info['token']['symbol']  # noqa
    update.message.reply_text(
        "🏆 List of pool rewards:"
    )
    if rewards_response:
        for reward in rewards_response:
            rewards += f"ID: {reward['id']} - rewards size: {reward['withdrawAmount']} {token}\n"
        update.message.reply_text(rewards)
    return ConversationHandler.END


import random

def initialize(self, runInfo, inputs):
  seed = 9491
  random.seed(seed)

def run(self,Input):
  # intput:
  # output:

  if self.outcome_P1P2 == 0:
    self.cost_P1P2 = 0.
  elif self.outcome_P1P2 == 2:
    numberDaysPred   = float(random.randint(2,7))
    costPerDayPred   = 0.3 * (0.8 + 0.4 * random.random())
    self.cost_P1P2   = numberDaysPred * costPerDayPred
  elif self.outcome_P1P2 == 3:
    numberDaysSD = float(random.randint(7,21))
    costPerDaySD = 0.8 + 0.4 * random.random()
    costSD       = numberDaysSD * costPerDaySD

    costPerDayReg = 0.2 + 0.1 * random.random()
    costReg       = numberDaysSD * costPerDayReg

    self.cost_P1P2 = costSD + costReg
  else:
    print('error costP1P2')

  self.p_P1P2_cost = self.p_P1P2_ET
  self.t_P1P2_cost = self.t_P1P2_ET


from ..utils.Initializers import get_initializer
from ..utils.Activator import get_activator
from ..utils.ConvCol import im2col,col2im
from .Base import Layer,Variable
import numpy as np

class Conv2D(Layer):
    def __init__(self, filter_nums, filter_size, input_shape=None, stride=1, padding='VALID', activation='linear',
                 initializer='Normal'):
        self.filter_nums = filter_nums
        self.filter_size = filter_size
        self.input_shape = input_shape
        self.stride = stride
        self.padding = padding
        self.activator = get_activator(activation)
        self.initializer = get_initializer(initializer)
        super(Conv2D, self).__init__(input_shape=input_shape)

    def connect(self, prev_layer):
        if prev_layer is None:
            assert self.input_shape is not None
            input_shape = self.input_shape

        else:
            input_shape = prev_layer.output_shape
            Layer.connect(self, prev_layer)

        assert len(input_shape) == 4
        batch_nums, n_C_prev, n_H_prev, n_W_prev, = input_shape
        filter_h, filter_w = self.filter_size

        assert self.padding.__class__.__name__ == 'str'
        self.padding = self.padding.upper()
        if self.padding == 'SAME':
            n_H = n_H_prev
            n_W = n_W_prev
            pad_h = (self.stride * (n_H_prev - 1) - n_H_prev + filter_h) // 2
            pad_w = (self.stride * (n_W_prev - 1) - n_W_prev + filter_w) // 2

            self.pad_size = (pad_h, pad_w)
        elif self.padding == 'VALID':
            n_H = (n_H_prev - filter_h) // self.stride + 1
            n_W = (n_W_prev - filter_w) // self.stride + 1

            self.pad_size = (0, 0)
        else:
            raise TypeError('Unknown padding type!plz inputs SAME or VALID')

        self.output_shape = (batch_nums, self.filter_nums, n_H, n_W)

        W = Variable(self.initializer((self.filter_nums, n_C_prev, filter_h, filter_w)))
        b = Variable(np.random.randn(1, self.filter_nums))
        W.grads = np.zeros_like(W.output_tensor) if W.require_grads else None
        b.grads = np.zeros_like(b.output_tensor) if b.require_grads else None
        self.variables.append(W)
        self.variables.append(b)

    def __call__(self, prev_layer):

        super(Conv2D, self).__call__(prev_layer)
        batch_nums, n_C_prev, n_H_prev, n_W_prev, = self.input_shape
        filter_h, filter_w = self.filter_size

        assert self.padding.__class__.__name__ == 'str'
        self.padding = self.padding.upper()
        if self.padding == 'SAME':
            n_H = n_H_prev
            n_W = n_W_prev
            pad_h = (self.stride * (n_H_prev - 1) - n_H_prev + filter_h) // 2
            pad_w = (self.stride * (n_W_prev - 1) - n_W_prev + filter_w) // 2

            self.pad_size = (pad_h, pad_w)
        elif self.padding == 'VALID':
            n_H = (n_H_prev - filter_h) // self.stride + 1
            n_W = (n_W_prev - filter_w) // self.stride + 1

            self.pad_size = (0, 0)
        else:
            raise TypeError('Unknown padding type!plz inputs SAME or VALID')

        self.output_shape = (batch_nums, self.filter_nums, n_H, n_W)
        W = Variable(self.initializer((self.filter_nums, n_C_prev, filter_h, filter_w)))
        b = Variable(np.random.randn(1, self.filter_nums))
        W.grads = np.zeros_like(W.output_tensor) if W.require_grads else None
        b.grads = np.zeros_like(b.output_tensor) if b.require_grads else None
        self.variables.append(W)
        self.variables.append(b)

        return self

    def _initial_params(self, *args):
        batch_nums, n_C_prev, n_H_prev, n_W_prev, = self.input_shape
        filter_h, filter_w = self.filter_size

        W = Variable(self.initializer((self.filter_nums, n_C_prev, filter_h, filter_w)))
        b = Variable(np.random.randn(self.filter_nums, ))

        self.variables.append(W)
        self.variables.append(b)
        for var in self.variables:
            if var.require_grads:
                var.grads = np.zeros_like(var.output_tensor)

    # def forward(self,is_training=True):
    #     W,b=self.variables
    #     # pad
    #     inputs = np.pad(self.input_tensor, ((0, 0), (0, 0), self.pad_size, self.pad_size), 'constant')
    #     # padded size
    #     batch_nums = inputs.shape[0]
    #     _,n_C,n_H,n_W=self.output_shape
    #
    #     col=im2col(inputs,self.output_shape,self.filter_size,self.stride)
    #
    #     col_W=W.output_tensor.reshape(self.filter_nums,-1).T
    #
    #     output=col.dot(col_W)+b.output_tensor
    #     output=output.reshape(batch_nums,n_H,n_W,-1).transpose(0,3,1,2)
    #     self.output_tensor=self.activator._forward(output)
    #
    #     #store it for bp
    #     if is_training:
    #         self.input_shape=self.input_tensor.shape
    #         self.col = col
    #         self.col_W=col_W
    #         if self.require_grads:
    #             self.grads = np.zeros_like(self.output_tensor)
    #
    #     super().forward(is_training)

    def forward(self, is_training=True):
        # copyright:from standford cs231n
        kernel, b = self.variables
        # before pading shape
        X = self.input_tensor
        self.input_shape = X.shape
        N, C, H, W = self.input_shape
        F, _, HH, WW = kernel.output_tensor.shape
        # pad
        X_padded = np.pad(X, ((0, 0), (0, 0), self.pad_size, self.pad_size), 'constant')

        out_h, out_w = self.output_shape[2:]
        shape = (C, HH, WW, N, out_h, out_w)
        strides = (H * W, W, 1, C * H * W, self.stride * W, self.stride)
        strides = X.itemsize * np.array(strides)
        X_stride = np.lib.stride_tricks.as_strided(X_padded, shape=shape, strides=strides)
        X_cols = np.ascontiguousarray(X_stride)
        X_cols.shape = (C * HH * WW, N * out_h * out_w)
        res = kernel.output_tensor.reshape(F, -1).dot(X_cols) + b.output_tensor.reshape(-1, 1)
        res.shape = (F, N, out_h, out_w)
        out = res.transpose(1, 0, 2, 3)
        output = np.ascontiguousarray(out)

        self.output_tensor = self.activator._forward(output)

        # store it for bp
        if is_training:
            self.cols = X_cols
            if self.require_grads:
                self.grads = np.zeros_like(self.output_tensor)
        super().forward(is_training)

    # def backward(self):
    #     W,b=self.variables
    #     grads=self.activator._backward(self.grads)
    #     filter_nums,n_C,filter_h,filter_w=W.output_shape
    #     grads=grads.transpose(0,2,3,1).reshape(-1,filter_nums)
    #     if W.require_grads:
    #         dW = self.col.T.dot(grads)
    #         W.grads += dW.transpose(1, 0).reshape(filter_nums, n_C, filter_h, filter_w)
    #     if b.require_grads:
    #         b.grads += np.sum(grads,axis=0)
    #     for layer in self.inbounds:
    #         if layer.require_grads:
    #             dcol = grads.dot(self.col_W.T)
    #             layer.grads+=col2im(self.input_shape,self.pad_size,self.filter_size,self.stride,dcol)
    #         else:
    #             layer.grads=grads
    #     del self.output_tensor

    def backward(self):
        # copyright:from standford cs231n
        kernel, b = self.variables
        grads = self.activator._backward(self.grads)

        N, C, H, W = self.input_tensor.shape
        F, _, HH, WW = kernel.output_tensor.shape
        _, _, out_h, out_w = grads.shape

        if b.require_grads:
            b.grads += np.sum(grads, axis=(0, 2, 3))

        grads_reshaped = grads.transpose(1, 0, 2, 3).reshape(F, -1)

        if kernel.require_grads:
            kernel.grads += grads_reshaped.dot(self.cols.T).reshape(F, C, HH, WW)

        for layer in self.inbounds:
            if layer.require_grads:
                dcol = grads_reshaped.T.dot(kernel.output_tensor.reshape(F, -1))
                layer.grads += col2im(self.input_shape, self.pad_size, self.filter_size, self.stride, dcol)
            else:
                layer.grads = grads
        del self.output_tensor

class ZeroPadding2D(Layer):
    def __init__(self,pad_size):
        assert len(pad_size)==2
        self.pad_h,self.pad_w=pad_size
        self.require_grads=False
        super(ZeroPadding2D,self).__init__()

    def connect(self,prev_layer):
        (batch_nums,C,H,W)=prev_layer.output_shape
        self.output_shape = (batch_nums,C,H+2*self.pad_h,W+2*self.pad_w)
        Layer.connect(self, prev_layer)

    def __call__(self,prev_layer):
        super(ZeroPadding2D,self).__call__(prev_layer)
        (batch_nums, C, H, W) = self.input_shape
        self.output_shape = (batch_nums, C, H + 2 * self.pad_h, W + 2 * self.pad_w)
        return self

    def forward(self,is_training=True):
        inputs=self.input_tensor
        self.output_tensor = np.pad(inputs, ((0, 0), (0, 0), (self.pad_h,self.pad_h), (self.pad_w,self.pad_w)), 'constant')
        if is_training:
            if self.require_grads:
                self.grads=np.zeros_like(inputs)
        del inputs
        super().forward(is_training)

    def backward(self):
        for layer in self.inbounds:
            if layer.require_grads:
                layer.grads+=self.grads[:,:,self.pad_h:-self.pad_h,self.pad_w:-self.pad_w]
            else:
                layer.grads=self.grads

class MaxPooling2D(Layer):
    def __init__(self, pool_size, stride=None):
        assert len(pool_size) == 2
        assert pool_size[0] == pool_size[1]
        self.pool_size = pool_size
        self.stride = pool_size[0] if stride is None else stride
        super(MaxPooling2D, self).__init__()

    def connect(self, prev_layer):
        batch_nums, n_C, n_H_prev, n_W_prev = prev_layer.output_shape
        pool_h, pool_w = self.pool_size
        assert pool_w == pool_h
        if pool_h == pool_w == self.stride:
            self.mode = 'reshape'
        else:
            self.mode = 'im2col'
        n_H, n_W = (n_H_prev - pool_h) // self.stride + 1, (n_W_prev - pool_w) // self.stride + 1
        self.output_shape = (batch_nums, n_C, n_H, n_W)
        Layer.connect(self, prev_layer)

    def __call__(self, prev_layer):
        super(MaxPooling2D, self).__call__(prev_layer)
        batch_nums, n_C, n_H_prev, n_W_prev = self.input_shape
        pool_h, pool_w = self.pool_size
        assert pool_w == pool_h
        if pool_h == pool_w == self.stride:
            self.mode = 'reshape'
        else:
            self.mode = 'im2col'
        n_H, n_W = (n_H_prev - pool_h) // self.stride + 1, (n_W_prev - pool_w) // self.stride + 1
        self.output_shape = (batch_nums, n_C, n_H, n_W)
        return self

    def forward(self, is_training=True):
        if self.mode == 'reshape':
            self.reshape_forward(self.input_tensor, self.pool_size, is_training)
        elif self.mode == 'im2col':
            self.im2col_forward(self.input_tensor, self.pool_size, self.stride, is_training)

        super().forward(is_training)

    def im2col_forward(self, x, pool_size, stride, is_training=True):
        _, n_C, n_H, n_W = self.output_shape
        batch_nums = x.shape[0]

        col = im2col(x, self.output_shape, pool_size, stride)
        pool_h, pool_w = pool_size
        col = col.reshape(-1, pool_h * pool_w)

        pool_argmax = np.argmax(col, axis=1)

        outputs = np.max(col, axis=1)
        self.output_tensor = outputs.reshape(batch_nums, n_H, n_W, n_C).transpose(0, 3, 1, 2)
        if is_training:
            self.input_shape = x.shape
            self.argmax_index = pool_argmax
            if self.require_grads:
                self.grads = np.zeros_like(self.output_tensor)
            del x

    def reshape_forward(self, x, pool_size, is_training=True):
        pool_height, pool_width = pool_size
        # _, n_C, n_H, n_W = self.output_shape
        N, C, H, W = x.shape
        x_reshaped = x.reshape(N, C, H // pool_height, pool_height, W // pool_width, pool_width)
        self.output_tensor = x_reshaped.max(axis=3).max(axis=4)
        if is_training:
            self.x_reshaped = x_reshaped
            if self.require_grads:
                self.grads = np.zeros_like(self.output_tensor)

    def backward(self):
        if self.mode == 'reshape':
            self.reshape_backward()
        elif self.mode == 'im2col':
            self.im2col_backward()

    def im2col_backward(self):
        grads = self.grads.transpose(0, 2, 3, 1)
        pool_h, pool_w = self.pool_size
        dmax = np.zeros((grads.size, pool_h * pool_w))
        dmax[np.arange(self.argmax_index.size), self.argmax_index.flatten()] = grads.flatten()
        dmax = dmax.reshape(grads.shape + (pool_h * pool_w,))

        dcol = dmax.reshape(np.prod(dmax.shape[:3]), -1)
        outputs = col2im(self.input_shape, (0, 0), self.pool_size, self.stride, dcol)
        for layer in self.inbounds:
            if layer.require_grads:
                layer.grads += outputs
            else:
                layer.grads = self.grads

    def reshape_backward(self):

        dx_reshaped = np.zeros_like(self.x_reshaped)
        out_newaxis = self.output_tensor[:, :, :, np.newaxis, :, np.newaxis]
        mask = (self.x_reshaped == out_newaxis)
        dout_newaxis = self.grads[:, :, :, np.newaxis, :, np.newaxis]
        dout_broadcast, _ = np.broadcast_arrays(dout_newaxis, dx_reshaped)
        dx_reshaped[mask] = dout_broadcast[mask]
        dx_reshaped /= np.sum(mask, axis=(3, 5), keepdims=True)
        outputs = dx_reshaped.reshape(self.input_tensor.shape)
        for layer in self.inbounds:
            if layer.require_grads:
                layer.grads += outputs
            else:
                layer.grads = self.grads

class MeanPooling2D(Layer):
    def __init__(self,pool_size,stride=None):
        assert len(pool_size)==2
        assert pool_size[0]==pool_size[1]
        self.pool_size=pool_size
        self.stride=pool_size[0] if stride is None else stride
        super(MeanPooling2D,self).__init__()

    def connect(self,prev_layer):
        batch_nums,n_C,n_H_prev,n_W_prev=prev_layer.output_shape
        pool_h,pool_w=self.pool_size
        n_H,n_W=(n_H_prev-pool_h)//self.stride+1,(n_W_prev-pool_w)//self.stride+1
        self.output_shape=(batch_nums,n_C,n_H,n_W)
        Layer.connect(self, prev_layer)

    def __call__(self,prev_layer):
        super(MeanPooling2D,self).__call__(prev_layer)
        batch_nums, n_C, n_H_prev, n_W_prev = self.input_shape
        pool_h, pool_w = self.pool_size
        n_H, n_W = (n_H_prev - pool_h) // self.stride + 1, (n_W_prev - pool_w) // self.stride + 1
        self.output_shape = (batch_nums, n_C, n_H, n_W)
        return self

    def forward(self,is_training=True):
        inputs = self.input_tensor
        _, n_C, n_H, n_W = self.output_shape
        batch_nums=inputs.shape[0]

        col = im2col(inputs,self.output_shape,self.pool_size,self.stride)
        pool_h,pool_w=self.pool_size
        col = col.reshape(-1, pool_h * pool_w)

        pool_argmean = np.array([range(col.shape[1])])

        outputs = np.mean(col, axis=1)
        self.output_tensor = outputs.reshape(batch_nums, n_H, n_W, n_C).transpose(0, 3, 1, 2)
        if is_training:
            self.inputs_shape = inputs.shape
            self.argmean_index = pool_argmean
            if self.require_grads:
                self.grads = np.zeros_like(self.output_tensor.value)
            del inputs
        super().forward(is_training)

    def backward(self):
        grads = self.grads.transpose(0, 2, 3, 1)
        pool_h,pool_w=self.pool_size

        dmean=np.repeat(grads.flatten(),self.argmean_index.size)/(pool_w*pool_h)
        dmean = dmean.reshape(grads.shape + (pool_h*pool_w,))

        dcol = dmean.reshape(np.prod(dmean.shape[:3]), -1)
        outputs = col2im(self.inputs_shape,(0,0),self.pool_size, self.stride, dcol)

        for layer in self.inbounds:
            if layer.require_grads:
                layer.grads += outputs
            else:
                layer.grads = grads
        del self.output_tensor