import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from google.colab import drive
drive.mount('/content/gdrive')
import pickle
from sklearn.preprocessing import OneHotEncoder
import datetime

path = '/content/gdrive/My Drive/DL_Project_Data/data.data'
with open(path, 'rb') as f:
  dataset = pickle.load(f)
images_temp = dataset['images']
alphabet = dataset['alphabets']
alphabet = np.reshape(np.array(alphabet), (234000, 1))
images = np.zeros((234000, 32, 32, 1))
for i in range(234000):
  images[i, :, :, 0] = images_temp[32*i:32*(i+1), :]
enc = OneHotEncoder(sparse=False)
alphabet_onehot = enc.fit_transform(alphabet)
train_data = images
train_labels = alphabet_onehot
ydim=26
zdim=100

def lkrelu(x, slope=0.01):
    return tf.maximum(slope * x, x)

def get_shape(tensor): # static shape
    return tensor.get_shape().as_list()

def batch_normalization(*args, **kwargs):
    with tf.name_scope('bn'):
        bn = tf.layers.batch_normalization(*args, **kwargs)
    return bn

def sample(X, y, length):
  max_len = len(X)
  idx =  np.random.randint(low=0, high=max_len, size=(length))
  return X[idx], y[idx]

# Define Discriminator
class Discriminator(object):
    def __init__(self, stddev=0.02):
        self.stddev = stddev

    def __call__(self, xs, ys, is_training, reuse=None):
        batch_dim = tf.shape(xs)[0]
        with tf.variable_scope('discriminator', initializer=tf.truncated_normal_initializer(stddev=self.stddev), reuse=reuse):
            with tf.variable_scope('conv1'):
                filters_1 = tf.get_variable('filters', [5, 5, 1, 32])
                conv_1 = tf.nn.conv2d(xs, filters_1, [1, 2, 2, 1], padding='SAME')

                # Adds y as a channel to conv_1 as described in ICGAN paper
                conv_1_concat_ys = tf.concat([conv_1, tf.tile(tf.reshape(ys, [-1, 1, 1, ys.get_shape()[-1]]),
                                                                [1, tf.shape(conv_1)[1], tf.shape(conv_1)[2], 1])], axis=3)
                a_1 = lkrelu(conv_1_concat_ys, slope=0.2)

            with tf.variable_scope('conv2'):
                filters_2 = tf.get_variable('filters', [5, 5, 32 + ydim, 32])
                conv_2 = tf.nn.conv2d(a_1, filters_2, [1, 2, 2, 1], padding='SAME')
                bn_2 = batch_normalization(conv_2,  center=False,
                            scale=False, training=is_training)
                a_2 = lkrelu(bn_2, slope=0.2)

            with tf.variable_scope('conv3'):
                filters_3 = tf.get_variable('filters', [5, 5, 32, 16])
                conv_3 = tf.nn.conv2d(a_2, filters_3, [1, 2, 2, 1], padding='SAME')
                bn_3 = batch_normalization(conv_3,  center=False,
                                            scale=False, training=is_training)
                a_3 = lkrelu(bn_3, slope=0.2)

            with tf.variable_scope('output'):
                  a_h = tf.layers.dense(tf.layers.flatten(a_3), 64)
                  a_o = tf.layers.dense(a_h, 1, activation='sigmoid')
        return a_o

# Define Generator
class Generator(object):
    def __init__(self, stddev=0.02):
        self.stddev = stddev

    def __call__(self, zs, ys, is_training):
        batch_dim = tf.shape(zs)[0]
        with tf.variable_scope('generator', initializer=tf.truncated_normal_initializer(stddev=self.stddev)):
            inputs = tf.concat([zs, ys], axis=1)
            with tf.variable_scope('volume'):
                z_p = tf.layers.dense(inputs, 4*4*128, activation='relu')
                bn_p = tf.layers.batch_normalization(z_p, training=is_training)
                reshaped_a_p = tf.reshape(bn_p, [-1, 4, 4, 128])
            with tf.variable_scope('deconv1'):
                deconv_1 = tf.layers.conv2d_transpose(reshaped_a_p, filters=64, kernel_size=5, strides=2, padding='same', activation='relu')
                bn_1 = tf.layers.batch_normalization(deconv_1, training=is_training)
            with tf.variable_scope('deconv2'):
                deconv_2 = tf.layers.conv2d_transpose(bn_1, filters=32, kernel_size=5, strides=2, padding='same', activation='relu')
                bn_2 = tf.layers.batch_normalization(deconv_2, training=is_training)

            with tf.variable_scope('deconv3'):
                deconv_3 = tf.layers.conv2d_transpose(bn_2, filters=16, kernel_size=5, strides=2, padding='same', activation='relu')
                bn_3 = tf.layers.batch_normalization(deconv_3, training=is_training)
                deconv_4 = tf.layers.conv2d_transpose(bn_3, filters=1, kernel_size=5, strides=1, padding='same', activation='tanh')
        return deconv_4

class CDCGAN(object):
    def __init__(self, zdim, ydim, xshape, lr=0.00005, beta1=0.5):
        self.is_training = tf.placeholder(tf.bool)

        self.zs = tf.placeholder(tf.float32, [None, zdim])
        self.g_ys = tf.placeholder(tf.float32, [None, ydim])

        self.xs = tf.placeholder(tf.float32, [None] + xshape)
        self.d_ys = tf.placeholder(tf.float32, [None, ydim])

        self.generator = Generator()
        self.discriminator = Discriminator()

        self.generator_output = self.generator(self.zs, self.g_ys, self.is_training)
        self.real_discriminator_output = self.discriminator(self.xs, self.d_ys, self.is_training)
        self.fake_discriminator_output = self.discriminator(self.generator_output, self.g_ys, self.is_training, reuse=True)

        self.generator_loss = -tf.reduce_mean(tf.log(self.fake_discriminator_output))
        self.discriminator_loss = -tf.reduce_mean(tf.log(self.real_discriminator_output) + tf.log(1.0 - self.fake_discriminator_output))

        g_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS, scope='generator')
        with tf.control_dependencies(g_update_ops):
            self.generator_train_step = tf.train.RMSPropOptimizer(lr).minimize(self.generator_loss,
                                        var_list=tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='generator'))
        d_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS, scope='discriminator')
        with tf.control_dependencies(d_update_ops):
            self.discriminator_train_step = tf.train.RMSPropOptimizer(lr).minimize(self.discriminator_loss,
                                            var_list=tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='discriminator'))

    def train_step(self, sess, xs, d_ys, zs, g_ys, is_training=True):
        _, dloss_curr = sess.run([self.discriminator_train_step, self.discriminator_loss],
                                    feed_dict={self.xs : xs, self.d_ys : d_ys, self.zs : zs, self.g_ys : d_ys, self.is_training : is_training})
        _, gloss_curr = sess.run([self.generator_train_step, self.generator_loss],
                                    feed_dict={self.zs : zs, self.g_ys : g_ys, self.is_training : is_training})
        return (gloss_curr, dloss_curr)

    def sample_generator(self, sess, zs, ys, is_training=True):
        return sess.run(self.generator_output, feed_dict={self.zs : zs, self.g_ys : ys, self.is_training : is_training})

batch_size = 128
epochs = 100000
draw_step = 500
model = CDCGAN(zdim, ydim, [32, 32, 1])
sess = tf.Session()
sess.run(tf.global_variables_initializer())
track_d_loss = []
track_g_loss = []
saver = tf.train.Saver()
sched = 10000
for epoch in range(epochs):
    if epoch % sched == 1 or epoch == 0:
      start = datetime.datetime.now()
    batch_xs, batch_ys = sample(train_data, train_labels, batch_size)
    gloss, dloss = model.train_step(sess, np.reshape(batch_xs, [-1, 32, 32, 1]),
                    batch_ys, np.random.uniform(-1, 1, (batch_size, zdim)), batch_ys)
    track_d_loss.append(dloss)
    track_g_loss.append(gloss)

    if epoch % sched == 0:
        saver.save(sess, './GAN_session.saved')
        imgs = model.sample_generator(sess, zs=np.repeat(np.random.uniform(-1, 1, (26, zdim)), 26, axis=0),
                                      ys=np.tile(np.eye(ydim), [26, 1]))

        fig = plt.figure()
        fig.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0.1)
        for i in range(26*26):
            fig.add_subplot(26, 26, i + 1)
            plt.imshow(imgs[i, :, :, 0], cmap='gray')
            plt.axis('off')
        plt.savefig('./iter_{}.png'.format(epoch))
        plt.show()
        plt.close()
        end = datetime.datetime.now()
        print('Epoch: {}/{},\t G loss: {:.4f}, D loss: {:.4f}\t| time: {}'.
          format(epoch, epochs, gloss, dloss, end-start))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Oct 17 15:09:54 2019

@author: burakgur
"""
import numpy as np
from numpy.fft import fft, fftfreq
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
#import sima # Commented out by seb
import copy
import scipy
from warnings import warn
from scipy import signal
from roipoly import RoiPoly
from scipy.optimize import curve_fit
from scipy.stats import linregress
from skimage import filters
from scipy.stats.stats import pearsonr
from scipy import fft
from scipy.signal import blackman
import course_functions.post_analysis_core as pac
import course_functions.process_mov_core_reduced_msc_course as pmc
class ROI_bg:
    """A region of interest from an image sequence """

    def __init__(self,Mask = None, experiment_info = None,imaging_info = None):
        """
        Initialized with a mask and optionally with experiment and imaging
        information
        """
        if (Mask is None):
            raise TypeError('ROI_bg: ROI must be initialized with a mask (numpy array)')
        if (experiment_info is not None):
            self.experiment_info = experiment_info
        if (imaging_info is not None):
            self.imaging_info = imaging_info

        self.mask = Mask
        self.uniq_id = id(self) # Generate a unique ID everytime

    def __str__(self):
        return '<ROI:{_id}>'.format(_id = self.uniq_id)

    def __repr__(self):
        return '<ROI:{_id}>'.format(_id = self.uniq_id)

    def setCategory(self,Category):
        self.category = Category

    def set_z_depth(self,depth):
        self.z_depth = depth

    def setSourceImage(self, Source_image):

        if np.shape(Source_image) == np.shape(self.mask):
            self.source_image = Source_image
        else:
            raise TypeError('ROI_bg: source image dimensions has to match with\
                            ROI mask.')

    def set_extraction_type(self,extraction_type):
        self.extraction_type = extraction_type

    def showRoiMask(self, cmap = 'Pastel2',source_image = None):

        if (source_image is None):
            source_image = self.source_image
        curr_mask = np.array(copy.deepcopy(self.mask),dtype=float)
        curr_mask[curr_mask==0] = np.nan
        sns.heatmap(source_image,alpha=0.8,cmap = 'gray',cbar=False)
        sns.heatmap(curr_mask, alpha=0.6,cmap = cmap,cbar=False)
        plt.axis('off')
        plt.title(self)

    def calculateDf(self,method='mean',moving_avg = False, bins = 3):
        try:
            self.raw_trace
        except NameError:
            raise NameError('ROI_bg: for deltaF calculations, a raw trace \
                            needs to be provided: a.raw_trace')

        if method=='mean':
            df_trace = (self.raw_trace-self.raw_trace.mean(axis=0))/(self.raw_trace.mean(axis=0))
            self.baseline_method = method

        if moving_avg:
            self.df_trace = movingaverage(df_trace, bins)
        else:
            self.df_trace = df_trace

        return self.df_trace

    def plotDF(self, line_w = 1, adder = 0,color=plt.cm.Dark2(0)):

        plt.plot(self.df_trace+adder, lw=line_w, alpha=.8,color=color)

        try:
            self.stim_info['output_data']
            stim_frames = self.stim_info['output_data'][:,7]  # Frame information
            stim_vals = self.stim_info['output_data'][:,3] # Stimulus value
            uniq_frame_id = np.unique(stim_frames,return_index=True)[1]
            stim_vals = stim_vals[uniq_frame_id]
            # Make normalized values of stimulus values for plotting

            stim_vals = (stim_vals/np.max(np.unique(stim_vals))) \
                *np.max(self.df_trace+adder)
            plt.plot(stim_vals,'--', lw=1, alpha=.6,color='k')
        except KeyError:
            print('No raw stimulus information found')

    def appendTrace(self, trace, epoch_num, trace_type = 'whole'):

        if trace_type == 'whole':
            try:
                self.whole_trace_all_epochs
            except AttributeError:
                self.whole_trace_all_epochs = {}

            self.whole_trace_all_epochs[epoch_num] = trace

        elif trace_type == 'response':
            try:
                self.resp_trace_all_epochs
            except AttributeError:
                self.resp_trace_all_epochs = {}

            self.resp_trace_all_epochs[epoch_num] = trace

    def appendStimInfo(self, Stim_info ,raw_stim_info = None):

        self.stim_info = Stim_info
        self.stim_name = Stim_info['stim_name']

        if (raw_stim_info is not None):
            # This part is now stored in the stim_info already but keeping it
            # for backward compatibility.
            self.raw_stim_info = raw_stim_info

    def findMaxResponse_all_epochs(self):
        try:
            self.resp_trace_all_epochs
        except AttributeError:
            raise AttributeError('ROI_bg: for finding maximum responses \
                            "resp_trace_all_epochs" has to be appended by \
                            appendTrace() method ')

        self.max_resp_all_epochs = \
            np.empty(shape=(int(self.stim_info['EPOCHS']),1)) #Seb: epochs_number --> EPOCHS

        self.max_resp_all_epochs[:] = np.nan

        for epoch_idx in self.resp_trace_all_epochs:
            self.max_resp_all_epochs[epoch_idx] = np.nanmax(self.resp_trace_all_epochs[epoch_idx])

        self.max_response = np.nanmax(self.max_resp_all_epochs)
        self.max_resp_idx = np.nanargmax(self.max_resp_all_epochs)

    def calculate_DSI_PD(self,method='PDND'):
        '''Calcuates DSI and PD of an ROI '''

        try:
            self.max_resp_all_epochs
            self.max_resp_idx
            self.stim_info
            self.max_response
        except AttributeError:
            raise TypeError('ROI_bg: for finding DSI an ROI needs\
                                 max_resp_all_epochs and stim_info')
        def find_opp_epoch(self, current_dir, current_freq, current_epoch_type):
            required_epoch_array = \
                    (self.stim_info['epoch_dir'] == ((current_dir+180) % 360)) & \
                    (self.stim_info['epoch_frequency'] == current_freq) & \
                    (self.stim_info['stimtype'] == current_epoch_type)

            return np.where(required_epoch_array)[0]

        if method == 'PDND':
            # Finding the maximum response epoch properties
            current_dir = self.stim_info['epoch_dir'][self.max_resp_idx]
            current_freq = self.stim_info['epoch_frequency'][self.max_resp_idx]
            current_epoch_type = self.stim_info['stimtype'][self.max_resp_idx]

            if current_freq == 0:
                warn('ROI %s -- max response is not in a moving epoch...' % self.uniq_id)
                moving_epochs = np.where(self.stim_info['epoch_frequency']>0)[0]
                # Find the moving epoch with max response
                idx = np.nanargmax(self.max_resp_all_epochs[moving_epochs])
                max_epoch = moving_epochs[idx]
                max_resp = self.max_resp_all_epochs[max_epoch]

            else:

                max_epoch = self.max_resp_idx
                max_resp = self.max_response
            # Calculating the DSI

            opposite_dir_epoch = find_opp_epoch(self,current_dir, current_freq,
                                                current_epoch_type)
            DSI = (max_resp - self.max_resp_all_epochs[opposite_dir_epoch])/\
                (max_resp + self.max_resp_all_epochs[opposite_dir_epoch])
            self.DSI = DSI[0][0]

            self.PD = current_dir

        elif method =='vector':
            dirs = self.stim_info['epoch_dir'][self.stim_info['baseline_epoch']+1:]
            resps = self.max_resp_all_epochs[self.stim_info['baseline_epoch']+1:]

            # Functions work with radians so convert
            xs= np.transpose(resps)*np.cos(np.radians(dirs))
            ys = np.transpose(resps)*np.sin(np.radians(dirs))
            x = (xs).sum()
            y = (ys).sum()
            DSI_vector = [x, y]
            cosine_angle = np.dot(DSI_vector, [1,0]) / (np.linalg.norm(DSI_vector) * np.linalg.norm([1,0]))

            # origin = [0], [0] # origin point
            # for idx,direction in enumerate(dirs):
            #     plt.quiver(origin[0],origin[1], xs[0][idx],ys[0][idx],
            #                color=plt.cm.Dark2(idx),
            #                label=str(direction),scale=2)
            # plt.quiver(origin[0],origin[1], x, y, color='r',scale=6)
            # plt.legend()

            angle = np.degrees(np.arccos(cosine_angle))
            if y<0:
                angle = 360 - angle
            self.DSI  = np.linalg.norm(DSI_vector)/np.max(resps)
            self.PD = angle

    def calculate_CSI(self, frameRate = None):

        try:
            self.resp_trace_all_epochs
            self.stim_info

        except AttributeError:
            raise TypeError('ROI_bg: for finding CSI an ROI needs\
                                 resp_trace_all_epochs and stim_info')
        # Find edge epochs
        edge_epochs = np.where(self.stim_info['stimtype']==50)[0]
        epochDur= self.stim_info['epochs_duration']

        self.edge_response = np.max(self.max_resp_all_epochs[edge_epochs])
        # Find the edge epoch with max response
        idx = np.nanargmax(self.max_resp_all_epochs[edge_epochs])
        max_edge_epoch = edge_epochs[idx]

        raw_trace = self.resp_trace_all_epochs[max_edge_epoch]
        trace = raw_trace
        # Filtering to decrease noise in max detection
#        b, a = signal.butter(3, 0.3, 'low')
#        trace = signal.filtfilt(b, a, raw_trace)

        half_dur_frames = int((round(self.imaging_info['frame_rate'] * epochDur[max_edge_epoch]))/2)
        OFF_resp = np.nanmax(trace[:half_dur_frames])
        ON_resp = np.nanmax(trace[half_dur_frames:])
        CSI = (ON_resp-OFF_resp)/(ON_resp+OFF_resp)

        self.CSI = np.abs(CSI)
        if CSI >0:
            self.CS = 'ON'
        else:
            self.CS = 'OFF'

    def calculateTFtuning_BF(self):

        grating_epochs = np.where(((self.stim_info['stimtype'] == 61) | \
                                   (self.stim_info['stimtype'] == 46)) &\
                                   (self.stim_info['epoch_frequency'] > 0))[0]

        # If there are no grating epochs
        if grating_epochs.size==0:
            raise ValueError('ROI_bg: No grating epoch (stim type: 61 or 46 \
                                                        exists.')

        max_grating_epoch=np.nanargmax(self.max_resp_all_epochs[grating_epochs])
        max_grating_epoch=grating_epochs[max_grating_epoch]

        current_dir = self.stim_info['epoch_dir'][max_grating_epoch]
        current_epoch_type = self.stim_info['stimtype'][max_grating_epoch]

        # Finding all same direction moving grating epochs
        required_epoch_array = \
                (self.stim_info['epoch_dir'] == current_dir) & \
                (self.stim_info['stimtype'] == current_epoch_type)& \
                (self.stim_info['epoch_frequency'] > 0)
        opposite_epoch_array = \
                (self.stim_info['epoch_dir'] == ((current_dir+180) % 360)) & \
                (self.stim_info['stimtype'] == current_epoch_type)& \
                (self.stim_info['epoch_frequency'] > 0)

        self.TF_curve_stim = self.stim_info['epoch_frequency'][required_epoch_array]

        self.ND_TF_curve_stim = self.stim_info['epoch_frequency'][opposite_epoch_array]
        # Get it as integer indices
        req_epochs_PD = np.where(required_epoch_array)[0]
        self.TF_curve_resp = self.max_resp_all_epochs[req_epochs_PD]

        req_epochs_ND = np.where(opposite_epoch_array)[0]
        self.ND_TF_curve_resp = self.max_resp_all_epochs[req_epochs_ND]

        self.BF = self.stim_info['epoch_frequency'][max_grating_epoch]

#%% The Class ROI_bg ends here and some other functions relating with ROIs will follow

def movingaverage(interval, window_size):
    window = np.ones(int(window_size))/float(window_size)
    return np.convolve(interval, window, 'same')

def interpolate_signal(signal, sampling_rate, int_rate):
    """
    """

     #juan: corrected interpolation
    period=1/sampling_rate
    timeV=  np.linspace(period,(len(signal)+1)*period,num=len(signal))
    # Create an interpolated time vector in the desired interpolation rate
    timeVI=np.linspace(0.1,10,100) #logic (period already interpolated,duration of trace(S),period*duration(s)) #careful if you change int_rate. Hardcoded line for 10hz interpolation of a 10sec stimulus
    return np.interp(timeVI, timeV, signal)

def find_inverted(rois,stim_type = None):
    """
    Calculate pearson's correlation between responses and stimulus.

    """
    for roi in rois:
        if stim_type == '1Hz_gratings':
            fr = roi.imaging_info['frame_rate']
            baseline_frames_total = roi.stim_info['baseline_duration'] * fr
            baseline_frames_needed = int(baseline_frames_total-(roi.stim_info['baseline_duration']/2.0 * fr))

            baseline_m = roi.whole_trace_all_epochs[1][baseline_frames_needed:int(baseline_frames_total)].mean()

            response_m = roi.resp_trace_all_epochs[1].mean()

            diff = response_m - baseline_m
            if diff>0:
                roi.inverted = 0
            else:
                roi.inverted = 1

        else:
            raise NameError('Stimulus type not found.')

    return rois

def generate_ROI_instances(roi_masks, category_masks, category_names, source_im,
                           experiment_info = None, imaging_info =None):
    """ Generates ROI_bg instances and adds the category information.

    Parameters
    ==========
    roi_masks : list
        A list of ROI masks in the form of numpy arrays.

    category_masks: list
        A list of category masks in the form of numpy arrays.

    category_names: list
        A list of category names.

    source_im : numpy array
        An array containing a representation of the source image where the
        ROIs are found.

    Returns
    =======

    rois : list
        A list containing instances of ROI_bg
    """
    # Seb: coommented this
    # if type(roi_masks) == sima.ROI.ROIList:
    #     roi_masks = list(map(lambda roi : np.array(roi)[0,:,:], roi_masks))

    # Generate instances of ROI_bg from the masks
    rois = list(map(lambda mask : ROI_bg(mask, experiment_info = experiment_info,
                                    imaging_info=imaging_info), roi_masks))

    def assign_region(roi, category_masks, category_names):
        """ Finds which layer the current mask is in"""
        for iLayer, category_mask in enumerate(category_masks):
            if np.sum(roi.mask*category_mask):
                roi.setCategory(category_names[iLayer])

    # Add information
    for roi in rois:
        assign_region(roi, category_masks, category_names)
        roi.setSourceImage(source_im)

    return rois

#%%
def data_to_list(rois, data_name_list):
    """ Generates a dictionary with desired variables from ROIs.

    Parameters
    ==========
    rois : list
        A list of ROI_bg instances.

    data_name_list: list
        A list of strings with desired variable names. The variables should be
        written as defined in the ROI_bg class.

    Returns
    =======

    roi_data_dict : dictionary
        A dictionary with keys as desired data variable names and values as
        list of data.
    """
    class my_dictionary(dict):

        # __init__ function
        def __init__(self):
            self = dict()

        # Function to add key:value
        def add(self, key, value):
            self[key] = value

    roi_data_dict = my_dictionary()

    # Generate an empty dictionary
    for key in data_name_list:
        roi_data_dict.add(key, [])

    # Loop through ROIs and get the desired data
    for iROI, roi in enumerate(rois):
        for key, value in roi_data_dict.items():
            if key in roi.__dict__.keys():
                value.append(roi.__dict__[key])
            else:
                value.append(np.nan)
    return roi_data_dict

def threshold_ROIs(rois, threshold_dict):
    """ Thresholds given ROIs and returns the ones passing the threshold.

    Parameters
    ==========
    rois : list
        A list of ROI_bg instances.

    threshold_dict: dict
        A dictionary with desired ROI_bg property names that will be
        thresholded as keys and the corresponding threshold values as values.

    Returns
    =======

    thresholded_rois : list
        A list containing instances of ROI_bg which pass the thresholding step.
    """
    # If there is no threshold
    if threshold_dict is None:
        print('No threshold used.')
        return rois
    vars_to_threshold = threshold_dict.keys()

    roi_data_dict = data_to_list(rois, vars_to_threshold)

    pass_bool = np.ones((1,len(rois)))

    for key, value in threshold_dict.items():

        if type(value) == tuple:
            if value[0] == 'b':
                pass_bool = \
                    pass_bool * (np.array(roi_data_dict[key]).flatten() > value[1])

            elif value[0] == 's':
                pass_bool = \
                    pass_bool * (np.array(roi_data_dict[key]).flatten() < value[1])
            else:
                raise TypeError("Tuple first value not understood: should be 'b' for bigger than or 's' for smaller than")

        else:
            pass_bool = pass_bool * (np.array(roi_data_dict[key]).flatten() > value)

    pass_indices = np.where(pass_bool)[1]

    thresholded_rois = []
    for idx in pass_indices:
        thresholded_rois.append(rois[idx])

    return thresholded_rois

#%%
def get_masks_image(rois):
    """ Generates an image of masks.

    Parameters
    ==========
    rois : list
        A list of ROI_bg instances.

    Returns
    =======

    roi_data_dict : np array
        A numpy array with masks depicted in different integers
    """
    roi_masks_image = np.array(list(map(lambda idx_roi_pair : \
                             idx_roi_pair[1].mask.astype(float) * (idx_roi_pair[0]+1),
                             list(enumerate(rois))))).sum(axis=0)

    roi_masks_image[roi_masks_image==0] = np.nan

    return roi_masks_image

#%%
def generate_colorMasks_properties(rois, prop = 'BF'):
    """ Generates images of masks depending on DSI CSI Rel and BF

    TODO: Is it possible to generate something independent?
    Parameters
    ==========
    rois : list
        A list of ROI_bg instances.

    Returns
    =======

    roi_data_dict : np array
        A numpy array with masks depicted in different integers
    """
    if prop == 'BF':
        BF_image = np.zeros(np.shape(rois[0].mask))

        for roi in rois:
            curr_mask = roi.mask.astype(int)
            BF_image = BF_image + (curr_mask * roi.BF)
        BF_image[BF_image==0] = np.nan

        return BF_image
    elif prop == 'CS':
        CSI_image = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_CS = roi.CS
            if curr_CS == 'OFF':
                curr_CSI = roi.CSI * -1
            else:
                curr_CSI = roi.CSI
            curr_mask = roi.mask.astype(int)
            CSI_image = CSI_image + (curr_mask * curr_CSI)
        CSI_image[CSI_image==0] = np.nan
        return CSI_image
    elif prop =='DSI':
        DSI_image  = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_DSI = roi.DSI

            curr_mask = roi.mask.astype(int)
            DSI_image = DSI_image + (curr_mask * curr_DSI)
        DSI_image[DSI_image==0] = np.nan
        return DSI_image
    elif prop =='PD':
        PD_image  = np.full(np.shape(rois[0].mask),np.nan)
        alpha_image  = np.full(np.shape(rois[0].mask),np.nan)
        for roi in rois:
            PD_image[roi.mask] = roi.PD
            alpha_image[roi.mask] = roi.DSI

        return PD_image

    elif prop == 'reliability':
        Corr_image = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_mask = roi.mask.astype(int)
            Corr_image = Corr_image + (curr_mask * roi.reliability)

        Corr_image[Corr_image==0] = np.nan
        return Corr_image

    elif prop == 'SNR':
        snr_image = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_mask = roi.mask.astype(int)
            snr_image = snr_image + (curr_mask * roi.SNR)

        snr_image[snr_image==0] = np.nan
        return snr_image
    elif prop == 'corr_fff':
        Corr_image = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_mask = roi.mask.astype(int)
            Corr_image = Corr_image + (curr_mask * roi.corr_fff)

        Corr_image[Corr_image==0] = np.nan
        return Corr_image
    elif prop == 'max_response':
        max_image = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_mask = roi.mask.astype(int)
            max_image = max_image + (curr_mask * roi.max_response)

        max_image[max_image==0] = np.nan
        return max_image
    elif prop == 'slope':

        slope_im = np.zeros(np.shape(rois[0].mask))
        for roi in rois:
            curr_mask = roi.mask.astype(int)
            slope_im = slope_im + (curr_mask * roi.slope)

        slope_im[slope_im==0] = np.nan
        return slope_im

    else:
        raise TypeError('Property %s not available for color mask generation' % prop)
        return 0

#%%
def analyze_gratings_general(rois):
    # IMPORTANT INFO
    # Seb: function name was changed from: analyze_luminance_gratings >>> analyze_gratings_general
    # The idea is to make one singl function handling all type of grating stimulation

    # Seb: if this variable does NOT exist in the stim file, made it 0 (= one single direction)
    if 'epoch_dir' in rois[0].stim_info:
        epoch_dirs = rois[0].stim_info['epoch_dir']
    else:
        epoch_dirs = np.ndarray.tolist(np.zeros(rois[0].stim_info['EPOCHS']))

    epoch_dirs_no_base= \
        np.delete(epoch_dirs,rois[0].stim_info['baseline_epoch'])
    epoch_types = rois[0].stim_info['stimtype']

    epoch_luminances= np.array(rois[0].stim_info['input_data']['lum'],float)
    epoch_velocity = np.array(rois[0].stim_info['input_data']['velocity'],float)
    epoch_sWavelength = np.array(rois[0].stim_info['input_data']['sWavelength'],float)
    epoch_TF= epoch_velocity/epoch_sWavelength

    if epoch_types[1] == 'noisygrating':
        epoch_SNR= np.array(rois[0].stim_info['input_data']['SNR'],float)

    for roi in rois:
        roi_dict = {}

        req_epochs = [e == rois[0].stim_info['stimtype'][-1] for e in epoch_types] # Seb: selecting epochs of interest based on the name of the last epoch in the stimulus input file
        if int(rois[0].stim_info['random']) == 1:
            req_epochs[0] = False # Seb: first epoch is for the baseline, not for analyzing any response
        #if rois[0].stim_info['stimtype'][0] != rois[0].stim_info['stimtype'][1]:
        #    req_epochs[0] = False
        #if rois[0].stim_info['stimtype'][0] == 'circle':
        #    req_epochs[0] = False #JC:4 times doing the same thing? commented it out

        roi_dict['luminance'] = epoch_luminances[req_epochs]
        roi_dict['deltaF'] = np.array(map(float,roi.max_resp_all_epochs[req_epochs]))
        roi_dict['TF'] = epoch_TF[req_epochs]
        # Specific variable based on the typ of stimulation for buiding a future heat map between this variable and TF
        if epoch_types[1] == 'lumgrating':
            variable_name = 'lum'

        elif epoch_types[1] == 'noisygrating':
            roi_dict['SNR'] = epoch_SNR[req_epochs]
            variable_name = 'SNR'

        elif epoch_types[1] == 'TFgrating':
            variable_name = 'TF'

        #Seb: fft analysis
        #epochs_roi_data= roi.whole_trace_all_epochs # try also just with roi.resp_trace_all_epochs
        epochs_roi_data = roi.resp_trace_all_epochs

        amp_fft = []
        for idx, epoch in enumerate(epochs_roi_data):
            curr_trace = epochs_roi_data[epoch]
            N = len(curr_trace) # frames or total number of points (aka sample rate)

            # FFT and power spectra calculations
            period = 1.0 / roi.imaging_info['frame_rate']
            yf = fft.fft(curr_trace) #JC: added fft. because the module changed and now
                                    #we need it to get the function
            xf = np.linspace(0.0, 1.0/(2.0*period), N//2)
            # mitigate spectral leakage
            w = np.blackman(N)
            ywf = fft.fft((curr_trace-curr_trace.mean())*w)

            # "X" Hz sinusoidal as reference
            Lx = N/roi.imaging_info['frame_rate'] # Duration in seconds
            X_Hz = round(roi_dict['TF'][idx],2)
            f = X_Hz * np.rint(Lx) # X_hz
            amp = 0.5 # desired amplitude
            x = np.arange(N)
            y = amp * np.sin(2 * np.pi * f * x / N)
            yf_ref = fft.fft(y) #fft values ref
            # yf_theo_ref = 2.0*np.abs(fft_values_ref/N)
            # mitigate spectral leakage
            w = np.blackman(N)
            ywf_ref = fft.fft((y-y.mean())*w)

            # Locating max peak of the reference frequency
            ref_trace_power = 2.0/N * np.abs(ywf_ref[1:N//2])
            m = max(ref_trace_power)
            max_idx = [i for i in range(len(ref_trace_power)) if ref_trace_power[i] == m][0]

            # Locating amplitude of the desired frequency in the response trace
            response_trace_power = 2.0/N * np.abs(ywf[1:N//2])
            temp_respose_amp = response_trace_power[max_idx]
            amp_fft.append(temp_respose_amp)

            # # plotting the spectrum
            # x_freqs = xf[1:N//2]

            # plt.close()
            # plt.plot(y)
            # plt.show()
            # plt.close()
            # plt.plot(x_freqs, response_trace_power, label='fft values')
            # plt.plot(x_freqs, ref_trace_power)
            # plt.plot(x_freqs[max_idx],temp_respose_amp, 'ro')
            # plt.title("Stimulated frequency (Hz): {}".format(X_Hz))
            # plt.show()
            # plt.close()

        # Saving the amplitude of the "X" hz component
        roi.fft_X_hz_amp = amp_fft

        # Seb: if this variable does NOT exist in the stim file, create it from others
        if 'epoch_TF' in rois[0].stim_info:
            roi_dict['TF'] = roi.stim_info['epoch_TF'][req_epochs]

        else:
            temp_TF_list = []
            for i, value in enumerate(roi.stim_info['velocity']):
                #Seb: if statement to take care of non-grating epoch
                if value == 0.0 and roi.stim_info['sWavelength'][i] == 0.0:
                    temp_TF = 0.0
                    temp_TF_list.append(temp_TF)
                    continue
                temp_TF = value/roi.stim_info['sWavelength'][i]
                temp_TF_list.append(temp_TF)

            temp_TF_list = np.array(temp_TF_list)
            roi.stim_info['epoch_TF'] = temp_TF_list
            roi_dict['TF'] = temp_TF_list[req_epochs]

        # Creating a pandas dataframe for future heat map
        df_roi = pd.DataFrame.from_dict(roi_dict)
        if epoch_types[1] == 'lumgrating':
            tfl_map = df_roi.pivot(index='TF',columns='luminance')
        elif epoch_types[1] == 'noisygrating':
            tfl_map = df_roi.pivot(index='TF',columns='SNR')
        elif epoch_types[1] == 'TFgrating':
            tfl_map = df_roi.pivot(index='TF',columns='luminance')

        roi.tfl_map= tfl_map
        roi.tfl_map_norm=(tfl_map-tfl_map.mean())/tfl_map.std()
        roi.BF = roi.stim_info['epoch_TF'][roi.max_resp_idx]

        conc_trace = []
        for epoch in np.argwhere((roi.stim_info['epoch_TF'] == 1))[1:]:

            conc_trace=np.append(conc_trace,
                                 roi.whole_trace_all_epochs[float(epoch)],axis=0)
        roi.oneHz_conc_resp = conc_trace

    return rois

def analyze_gratings_1Hz(rois,int_rate = 10):  # Previous name: analyze_luminance_gratings_1Hz

    # Seb: if this variable does NOT exist in the stim file, made it 0 (= one single direction)
    if 'epoch_dir' in rois[0].stim_info:
        epoch_dirs = rois[0].stim_info['epoch_dir']
    else:
        epoch_dirs = np.ndarray.tolist(np.zeros(rois[0].stim_info['EPOCHS']))

    epoch_dirs_no_base= \
        np.delete(epoch_dirs,rois[0].stim_info['baseline_epoch'])
    epoch_types = rois[0].stim_info['stimtype']

    if epoch_types[-1] == 'lumgrating':
        epoch_luminances= np.array(rois[0].stim_info['input_data']['lum'],float)
    elif epoch_types[-1] == 'noisygrating':
        epoch_luminances= np.array(rois[0].stim_info['input_data']['SNR'],float)

    for roi in rois:

        # Seb: commented this out
        # if not('1D' in roi.stim_name):
        #     curr_pref_dir = \
        #         np.unique(epoch_dirs_no_base)[np.argmin(np.abs(np.unique(epoch_dirs_no_base)-roi.PD))]
        #     req_epochs = (epoch_dirs==curr_pref_dir) & (epoch_types != 11)
        # else:
        #     req_epochs = (epoch_types != 11)

        req_epochs = [e == rois[0].stim_info['stimtype'][-1] for e in epoch_types] # Seb: selecting epochs of interest based on the name of the last epoch in the stimulus input file
        if rois[0].stim_info['stimtype'][0] == rois[0].stim_info['stimtype'][1]:
            req_epochs[0] = False

        roi.luminances = epoch_luminances[req_epochs]
        conc_trace = []
        roi.power_at_hz = np.zeros_like(roi.luminances)
        roi.base_power = np.zeros_like(roi.luminances)
        roi.baselines = np.zeros_like(roi.luminances)
        fr = roi.imaging_info['frame_rate']

        min_len = np.array(list(map(len, roi.resp_trace_all_epochs.values()))).min()
        traces = np.zeros((np.sum(req_epochs),min_len))

        ex_trace = roi.resp_trace_all_epochs[np.where(req_epochs)[0][0]][:min_len]
        int_len = len(interpolate_signal(ex_trace,
                                     roi.imaging_info['frame_rate'],int_rate))
        int_traces =np.zeros((np.sum(req_epochs),int_len))

        min_len_wholeT = np.array(list(map(len, roi.whole_trace_all_epochs.values()))).min()
        traces_wholeT = np.zeros((np.sum(req_epochs),min_len_wholeT))

        ex_trace_wholeT = roi.whole_trace_all_epochs[np.where(req_epochs)[0][0]][:min_len_wholeT]
        int_len_wholeT = len(interpolate_signal(ex_trace_wholeT,
                                     roi.imaging_info['frame_rate'],int_rate))
        int_traces_wholeT =np.zeros((np.sum(req_epochs),int_len_wholeT))
        mat_idx = 0
        for idx,epoch in enumerate(np.where(req_epochs)[0]):
            try:
                curr_freq = roi.stim_info['epoch_frequency'][epoch]
            except:
                curr_freq = roi.stim_info['epoch_TF'][epoch]
            curr_resp = roi.resp_trace_all_epochs[epoch]

            two_sec = int(2 * roi.imaging_info['frame_rate'])
            curr_whole = roi.whole_trace_all_epochs[epoch][two_sec:-1-two_sec]
            bg_resp = roi.whole_trace_all_epochs[epoch][two_sec:-two_sec+int(roi.imaging_info['frame_rate'])]
            bg_resp_mean = bg_resp.mean()
            roi.baselines[idx] = curr_resp[int(fr):].mean()-bg_resp_mean

            # Fourier analysis of baseline responses
            N = len(curr_whole)
            period = 1.0 / roi.imaging_info['frame_rate']
            x = np.linspace(0.0, N*period, N)
            yf = fft.fft(curr_whole)

            xf = np.linspace(0.0, 1.0/(2.0*period), N//2)
            # mitigate spectral leakage
            w = blackman(N)
            ywf = fft.fft((curr_whole-curr_whole.mean())*w)
            # plt.plot(xf[1:N//2], 2.0/N * np.abs(ywf[1:N//2]),
            #               label = '{l}'.format(l=roi.luminances[idx]))
            # plt.legend()
            base_p = 2.0/N * np.abs(ywf[1:N//2])
            req_idx = np.argmin(np.abs(xf-(1.0/6)))
            roi.base_power[idx] = base_p[req_idx]

            # Fourier analysis of sinusodial responses
            N = len(curr_resp)
            period = 1.0 / roi.imaging_info['frame_rate']
            x = np.linspace(0.0, N*period, N)
            yf = fft.fft(curr_resp)

            xf = np.linspace(0.0, 1.0/(2.0*period), N//2)
            # mitigate spectral leakage
            w = blackman(N)
            ywf = fft.fft((curr_resp-curr_resp.mean())*w)
            # plt.plot(xf[1:N//2], 2.0/N * np.abs(ywf[1:N//2]),
            #               label = '{l}'.format(l=roi.luminances[idx]))
            # plt.legend()
            power = 2.0/N * np.abs(ywf[1:N//2])
            req_idx = np.argmin(np.abs(xf-curr_freq))
            roi.power_at_hz[idx] = power[req_idx]

            # Concatenate trace
            conc_trace=np.append(conc_trace,
                                 roi.whole_trace_all_epochs[float(epoch)][two_sec:],axis=0)

            # Interpolation
            curr_trace = roi.resp_trace_all_epochs[epoch][:min_len]
            traces[mat_idx,:] = curr_trace
            int_traces[mat_idx,:] = interpolate_signal(curr_trace,
                                 roi.imaging_info['frame_rate'],int_rate)

            curr_trace_wt = roi.whole_trace_all_epochs[epoch][:min_len_wholeT]
            traces_wholeT[mat_idx,:] = curr_trace_wt
            int_traces_wholeT[mat_idx,:] = interpolate_signal(curr_trace_wt,
                                 roi.imaging_info['frame_rate'],int_rate)

            mat_idx +=1

        roi.int_rate = int_rate
        roi.grating_resp_traces = traces
        roi.grating_resp_traces_interpolated = int_traces

        roi.grating_whole_traces = traces_wholeT
        roi.grating_whole_traces_interpolated = int_traces_wholeT

        # plt.legend()
        # plt.title(roi.experiment_info['Genotype'])
        # plt.xlabel('Hz')
        # plt.ylabel('Signal')
        # plt.waitforbuttonpress()
        # plt.close('all')
        roi.conc_resp = conc_trace

        X = roi.luminances
        Y = roi.power_at_hz
        Z = roi.base_power

        roi.slope = linregress(X, np.transpose(Y))[0]
        roi.basePower_slope = linregress(X, np.transpose(Z))[0]
        roi.base_slope = linregress(X, np.transpose(roi.baselines))[0]

    return rois


import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np

import os
from collections import Counter
from argparse import Namespace

param = Namespace(
    train_file_path="语料/train_seg/train",
    checkpoint_path='checkpoint2',
    seq_size=32,
    batch_size=64,
    embedding_size=128, # embedding dimension
    lstm_size=128, # hidden dimension
    gradients_norm=5, # gradient clipping
    top_k=5,
    num_epochs=50,
    learning_rate=0.001
)

corpus_path = "语料/train_text/"  # 未分词分类预料库路径
seg_path = "语料/train_seg/train"  # 分词后分类语料库路径

catelist = os.listdir(seg_path)  # 获取未分词目录下所有子目录

word_to_int = {}

with open("word_dict.txt",'r',encoding = "utf-8") as fdict:
    for line in fdict.readlines():
        linelist = line.split()
        num = int(linelist[0])
        word = linelist[1]
        word_to_int[word] = num

int_to_word = {k: w for w,k in word_to_int.items()}

from torch.utils import data

class MyDataset(data.Dataset):
    def __init__(self,filepath, batch_size,seq_size):
        text = []
        file_list = os.listdir(filepath)
        for file_path in file_list:
            full_name = filepath + "/" + file_path
            #print("当前处理的文件是:",full_name)
            with open(full_name, "r", encoding="utf-8") as f:
                for line in f.readlines():
                    linelist = line.split()
                    newlist = []
                    for word in linelist:
                        if(len(word)>1):
                            newlist.append(word)
                    text += newlist

        int_data =[word_to_int[word] for word in text]
        num_bacthes = int(len(int_data) / (seq_size * batch_size) )
        x_data = int_data[:num_bacthes*batch_size *seq_size]
        y_data = np.zeros_like(x_data)
        y_data[:-1] = x_data[1:]
        y_data[-1] = x_data[0]

        self.x_data = np.reshape(x_data,(-1,seq_size))
        self.y_data = np.reshape(y_data,(-1,seq_size))

    def __len__(self):
        return len(self.x_data)
    def __getitem__(self, id):
        x = self.x_data[id]
        y = self.y_data[id]
        return x,y

class LSTMModule(nn.Module):
    def __init__(self,numWord,seq_size,embedding_size,lstm_size):
        super(LSTMModule,self).__init__()
        self.seq_size = seq_size
        self.lstm_size = lstm_size
        self.embedding =  nn.Embedding(numWord,embedding_size)

        self.lstm = nn.LSTM(embedding_size,lstm_size,batch_first = True)
        self.linear = nn.Linear(lstm_size,numWord)
    def forward(self,x,prestate):

        embedding = self.embedding(x)
        output,state = self.lstm(embedding,prestate)
        logits = self.linear(output)
        return logits, state
    #set zero state, used for setting up
    def zero_state(self,batch_size):
        return (torch.zeros(1,batch_size,self.lstm_size), torch.zeros(1,batch_size,self.lstm_size))

import time,sys

def train():
    if(torch.cuda.is_available()):
        device = torch.device('cuda')
    else:
        device = torch.device('cpu')
    train_data = MyDataset(param.train_file_path,param.batch_size,param.seq_size)
    train_loader = data.DataLoader(dataset = train_data,batch_size = param.batch_size,shuffle = False)
    network = LSTMModule(len(word_to_int), param.seq_size, param.embedding_size, param.lstm_size )
    network = network.to(device)

    criterion = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(network.parameters(), lr = param.learning_rate)
    iter = 0
    losses = []
    start_time = time.time()
    minloss = float("inf")
    for epoch in range(param.num_epochs):
        state_h, state_c = network.zero_state(param.batch_size)
        state_h, state_c = state_h.to(device),state_c.to(device)

        for i,(x,y) in enumerate(train_loader):
            iter += 1
            network.train()     #use train mode
            optimizer.zero_grad()    # 梯度清零
            x = x.long()
            y = y.long()
            x = torch.LongTensor(x).to(device)
            y = torch.LongTensor(y).to(device)      #转化模型输入为longtensor
            logits, (state_h,state_c) = network(x,(state_h,state_c))
            #print(logits.size(),y.size())

            loss = criterion(logits.transpose(1,2), y)

            loss_value = loss.item()

            state_h = state_h.detach()
            state_c = state_c.detach()

            loss.backward()

            _ = torch.nn.utils.clip_grad_norm_(network.parameters(),param.gradients_norm)

            optimizer.step()
            losses.append(loss_value)

            if iter %1000 == 0:
                torch.save(network.state_dict(),'{}/model-{}.pth'.format(param.checkpoint_path, iter))
            if loss_value < minloss:
                minloss = loss_value
                torch.save(network.state_dict(),'{}/model-final.pth'.format(param.checkpoint_path))
if __name__ == "__main__":
    train()


# -*- coding: UTF-8 -*-

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'                                                                         '
' Copyright 2018 Gauthier Brière (gauthier.briere "at" gmail.com)         '
'                                                                         '
' This file is part of cn5X++                                               '
'                                                                         '
' cn5X++ is free software: you can redistribute it and/or modify it         '
'  under the terms of the GNU General Public License as published by      '
' the Free Software Foundation, either version 3 of the License, or       '
' (at your option) any later version.                                     '
'                                                                         '
' cn5X++ is distributed in the hope that it will be useful, but           '
' WITHOUT ANY WARRANTY; without even the implied warranty of              '
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           '
' GNU General Public License for more details.                            '
'                                                                         '
' You should have received a copy of the GNU General Public License       '
' along with this program.  If not, see <http://www.gnu.org/licenses/>.   '
'                                                                         '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

import sys, time
from math import *
from PyQt5.QtCore import QCoreApplication, QObject, QThread, QTimer, QEventLoop, pyqtSignal, pyqtSlot, QIODevice
from PyQt5.QtSerialPort import QSerialPort, QSerialPortInfo
from cn5X_config import *
from grblComSerial import grblComSerial

class grblCom(QObject):
  '''
  Gestion du thread de communication serie avec Grbl
  '''

  # Reprise des signaux venant du thread de Com a faire suivre
  sig_log     = pyqtSignal(int, str) # Message de fonctionnement du composant grblComSerial, renvoie : logSeverity, message string
  sig_connect = pyqtSignal()         # Emis a la reception de la connexion
  sig_init    = pyqtSignal(str)      # Emis a la reception de la chaine d'initialisation de Grbl, renvoie la chaine complete
  sig_ok      = pyqtSignal()         # Emis a la reception de la chaine "ok"
  sig_error   = pyqtSignal(int)      # Emis a la reception d'une erreur Grbl, renvoie le N° d'erreur
  sig_alarm   = pyqtSignal(int)      # Emis a la reception d'une alarme Grbl, renvoie le N° d'alarme
  sig_status  = pyqtSignal(str)      # Emis a la reception d'un message de status ("<...|.>"), renvoie la ligne complete
  sig_config  = pyqtSignal(str)      # Emis a la reception d'une valeur de config ($XXX)
  sig_data    = pyqtSignal(str)      # Emis a la reception des autres donnees de Grbl, renvoie la ligne complete
  sig_emit    = pyqtSignal(str)      # Emis a l'envoi des donnees sur le port serie
  sig_recu    = pyqtSignal(str)      # Emis a la reception des donnees sur le port serie
  sig_debug   = pyqtSignal(str)      # Emis a chaque envoi ou reception

  # Signaux de pilotage a envoyer au thread
  sig_abort        = pyqtSignal()
  sig_gcodeInsert  = pyqtSignal(str, object)
  sig_gcodePush    = pyqtSignal(str, object)
  sig_realTimePush = pyqtSignal(str, object)
  sig_clearCom     = pyqtSignal()
  sig_startPooling = pyqtSignal()
  sig_stopPooling  = pyqtSignal()

  def __init__(self):
    super().__init__()
    self.__threads       = None
    self.__Com           = None
    self.__connectStatus = False
    self.__grblInit      = False
    self.__pooling       = True
    self.__grblVersion   = ""
    self.__grblStatus    = ""
    self.__threads = []

  def startCom(self, comPort: str, baudRate: int):
    '''
    Gestion des communications serie et des timers dans des threads distincts
    '''

    self.sig_debug.emit("grblCom.startCom(self, {}, {})".format(comPort, baudRate))

    self.sig_log.emit(logSeverity.info.value, 'grblCom: Starting grblComSerial thread.')
    newComSerial = grblComSerial(comPort, baudRate, self.__pooling)
    thread = QThread()
    thread.setObjectName('grblComSerial')
    self.__threads.append((thread, newComSerial))  # need to store worker too otherwise will be gc'd
    newComSerial.moveToThread(thread)

    # Connecte les signaux provenant du grblComSerial
    newComSerial.sig_log.connect(self.sig_log.emit)
    newComSerial.sig_connect.connect(self.on_sig_connect)
    newComSerial.sig_init.connect(self.on_sig_init)
    newComSerial.sig_ok.connect(self.sig_ok.emit)
    newComSerial.sig_error.connect(self.sig_error.emit)
    newComSerial.sig_alarm.connect(self.sig_alarm.emit)
    newComSerial.sig_status.connect(self.on_sig_status)
    newComSerial.sig_config.connect(self.sig_config.emit)
    newComSerial.sig_data.connect(self.sig_data.emit)
    newComSerial.sig_emit.connect(self.sig_emit.emit)
    newComSerial.sig_recu.connect(self.sig_recu.emit)
    newComSerial.sig_debug.connect(self.sig_debug.emit)

    # Signaux de pilotage a envoyer au thread
    self.sig_abort.connect(newComSerial.abort)
    self.sig_gcodeInsert.connect(newComSerial.gcodeInsert)
    self.sig_gcodePush.connect(newComSerial.gcodePush)
    self.sig_realTimePush.connect(newComSerial.realTimePush)
    self.sig_clearCom.connect(newComSerial.clearCom)
    self.sig_startPooling.connect(newComSerial.startPooling)
    self.sig_stopPooling.connect(newComSerial.stopPooling)

    # Start the thread...
    thread.started.connect(newComSerial.run)
    thread.start()  # this will emit 'started' and start thread's event loop

    # Memorise le communicateur
    self.__Com = newComSerial

  @pyqtSlot(bool)
  def on_sig_connect(self, value: bool):
    self.sig_debug.emit("grblCom.on_sig_connect(self, {})".format(value))
    ''' Maintien l'etat de connexion '''
    self.__connectStatus = value
    self.sig_connect.emit()

  @pyqtSlot(str)
  def  on_sig_init(self, buff: str):
    self.sig_debug.emit("grblCom.on_sig_init(self, {})".format(buff))
    self.__grblInit = True
    self.__grblVersion = buff.split("[")[0]
    self.sig_init.emit(buff)

  def grblVersion(self):
    ''' Renvoi la chaine Grbl vXXX '''
    return self.__grblVersion

  @pyqtSlot(str)
  def on_sig_status(self, buff: str):
    self.sig_debug.emit("grblCom.on_sig_status(self, {})".format(buff))
    ''' Memorise le status de Grbl a chaque fois qu'on en voi un passer '''
    self.__grblStatus = buff[1:].split('|')[0]
    self.sig_status.emit(buff)

  def grblStatus(self):
    ''' Renvoi le dernier status Grbl vu '''
    return self.__grblStatus

  def stopCom(self):
    self.sig_debug.emit("grblCom.stopCom(self)")
    ''' Stop le thread des communications serie '''
    self.clearCom() # Vide la file d'attente
    self.sig_log.emit(logSeverity.info.value, self.tr("Envoi signal sig_abort au thread de communications serie..."))
    self.sig_abort.emit()
    # Attente de la fin du (des) thread(s)
    for thread, worker in self.__threads:
        thread.quit()  # this will quit **as soon as thread event loop unblocks**
        thread.wait()  # <- so you need to wait for it to *actually* quit
    self.sig_log.emit(logSeverity.info.value, self.tr("Thread(s) enfant(s) termine(s)."))
    self.__grblInit = False
    self.__threads = []

  def gcodeInsert(self, buff: str, flag=COM_FLAG_NO_FLAG):
    if self.__connectStatus and self.__grblInit:
      self.sig_gcodeInsert.emit(buff, flag)
    else:
      self.sig_log.emit(logSeverity.warning.value, self.tr("grblCom: Grbl non connecte ou non initialise, [{}] impossible a envoyer").format(buff))

  def gcodePush(self, buff: str, flag=COM_FLAG_NO_FLAG):
    if self.__connectStatus and self.__grblInit:
      self.sig_gcodePush.emit(buff, flag)
    else:
      self.sig_log.emit(logSeverity.warning.value, self.tr("grblCom: Grbl non connecte ou non initialise, [{}] impossible a envoyer").format(buff))

  def realTimePush(self, buff: str, flag=COM_FLAG_NO_FLAG):
    if self.__connectStatus and self.__grblInit:
      self.sig_realTimePush.emit(buff, flag)
    else:
      self.sig_log.emit(logSeverity.warning.value, self.tr("grblCom: Grbl non connecte ou non initialise, [{}] impossible a envoyer").format(buff))

  def clearCom(self):
    self.sig_clearCom.emit()

  @pyqtSlot()
  def startPooling(self):
    self.__pooling = True
    self.sig_startPooling.emit()

  @pyqtSlot()
  def stopPooling(self):
    self.__pooling = False
    self.sig_stopPooling.emit()

  def isOpen(self):
    return self.__connectStatus


#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import (division, absolute_import, print_function,
                        unicode_literals, annotations)
from multiprocessing import Pool
import sys
import psutil
import tensorflow as tf

num_cpus = psutil.cpu_count(logical=False)

filename = '/tmp/model'

def evaluate_next_batch(i):
    # Pin the process to a specific core if we are on Linux to prevent
    # contention between the different processes since TensorFlow uses
    # multiple threads.
    if sys.platform == 'linux':
        psutil.Process().cpu_affinity([i])
    model = tf.keras.models.load_model(filename)
    mnist = tf.keras.datasets.mnist.load_data()
    x_test = mnist[1][0] / 255.0
    return model.predict(x_test)

def main():
    # Time the code below.

    pool = Pool(num_cpus)

    for _ in range(10):
        pool.map(evaluate_next_batch, range(num_cpus))

if __name__ == '__main__':
    main()


import numpy as np
#import matplotlib.pyplot as plt
from scipy.misc import imfilter, imread
from skimage import color, data, restoration
from scipy.signal import convolve2d as conv2

def main():
  image = imread("/Users/gsamaras/Downloads/boat.tif")
  #plt.imshow(arr, cmap='gray')
  #plt.show()
  #blurred_arr = imfilter(arr, "blur")
  psf = np.ones((5, 5)) / 25
  image = conv2(image, psf, 'same')
  image += 0.1 * image.std() * np.random.standard_normal(image.shape)

  deconvolved = restoration.wiener(image, psf, 1, clip=False)
  #print deconvolved
  plt.imshow(deconvolved, cmap='gray')
  plt.show()
  #print image

if __name__ == "__main__":
    main()


lucky_numbers = [5, 8, 11, 20, 24, 31, 43, 43] #some random numbers
friends = ["John", "Mike", "David", "Danny", "Joel", "Karen"] #random people

friends2 = friends.copy() #copy the list

friends.append("Creed") #this add something on the end of the list
friends.insert(1, "Robin") #this will add it into the list and delete that on the position

friends.remove("Danny") # remove the certain information from the list
friends.pop() #removes the last element of the list
friends.sort() #sort them by alphabet

print(friends.index("David")) #print the order of the character
print(lucky_numbers.count(43)) #counts how many times is the item on the list
print(friends)


import math
import copy
from torch import nn
import torch.nn.functional as F
import torch
from inspect import isfunction
from functools import partial

from torch.utils import data
from pathlib import Path
from torch.optim import Adam
from torchvision import transforms, utils

from einops import rearrange

from PIL import Image
from torch import linalg as LA

try:
    from apex import amp

    APEX_AVAILABLE = True
except:
    APEX_AVAILABLE = False

def exists(x):
    return x is not None

def default(val, d):
    if exists(val):
        return val
    return d() if isfunction(d) else d

def cycle(dl):
    while True:
        for data in dl:
            yield data

import numpy as np

def spiral_cw(A):
    A = np.array(A)
    out = []
    while(A.size):
        out.append(A[0])        # take first row
        A = A[1:].T[::-1]       # cut off first row and rotate counterclockwise
    return np.concatenate(out)

def spiral_ccw(A):
    A = np.array(A)
    out = []
    while(A.size):
        out.append(A[0][::-1])    # first row reversed
        A = A[1:][::-1].T         # cut off first row and rotate clockwise
    return np.concatenate(out)

def base_spiral(nrow, ncol):
    return spiral_ccw(np.arange(nrow*ncol).reshape(nrow,ncol))[::-1]

def to_spiral(A):
    A = np.array(A)
    B = np.empty_like(A)
    B.flat[base_spiral(*A.shape)] = A.flat
    return B

def from_spiral(A):
    A = np.array(A)
    return A.flat[base_spiral(*A.shape)].reshape(A.shape)

def to_spiral(A):
    A = np.array(A)
    B = np.empty_like(A)
    B.flat[base_spiral(*A.shape)] = A.flat
    return B

def from_spiral(A):
    A = np.array(A)
    return A.flat[base_spiral(*A.shape)].reshape(A.shape)

def loss_backwards(fp16, loss, optimizer, **kwargs):
    if fp16:
        with amp.scale_loss(loss, optimizer) as scaled_loss:
            scaled_loss.backward(**kwargs)
    else:
        loss.backward(**kwargs)

class EMA():
    def __init__(self, beta):
        super().__init__()
        self.beta = beta

    def update_model_average(self, ma_model, current_model):
        for current_params, ma_params in zip(current_model.parameters(), ma_model.parameters()):
            old_weight, up_weight = ma_params.data, current_params.data
            ma_params.data = self.update_average(old_weight, up_weight)

    def update_average(self, old, new):
        if old is None:
            return new
        return old * self.beta + (1 - self.beta) * new

class Residual(nn.Module):
    def __init__(self, fn):
        super().__init__()
        self.fn = fn

    def forward(self, x, *args, **kwargs):
        return self.fn(x, *args, **kwargs) + x

class SinusoidalPosEmb(nn.Module):
    def __init__(self, dim):
        super().__init__()
        self.dim = dim

    def forward(self, x):
        device = x.device
        half_dim = self.dim // 2
        emb = math.log(10000) / (half_dim - 1)
        emb = torch.exp(torch.arange(half_dim, device=device) * -emb)
        emb = x[:, None] * emb[None, :]
        emb = torch.cat((emb.sin(), emb.cos()), dim=-1)
        return emb

def Upsample(dim):
    return nn.ConvTranspose2d(dim, dim, 4, 2, 1)

def Downsample(dim):
    return nn.Conv2d(dim, dim, 4, 2, 1)

class LayerNorm(nn.Module):
    def __init__(self, dim, eps=1e-5):
        super().__init__()
        self.eps = eps
        self.g = nn.Parameter(torch.ones(1, dim, 1, 1))
        self.b = nn.Parameter(torch.zeros(1, dim, 1, 1))

    def forward(self, x):
        var = torch.var(x, dim=1, unbiased=False, keepdim=True)
        mean = torch.mean(x, dim=1, keepdim=True)
        return (x - mean) / (var + self.eps).sqrt() * self.g + self.b

class PreNorm(nn.Module):
    def __init__(self, dim, fn):
        super().__init__()
        self.fn = fn
        self.norm = LayerNorm(dim)

    def forward(self, x):
        x = self.norm(x)
        return self.fn(x)

class ConvNextBlock(nn.Module):
    """ https://arxiv.org/abs/2201.03545 """

    def __init__(self, dim, dim_out, *, time_emb_dim=None, mult=2, norm=True):
        super().__init__()
        self.mlp = nn.Sequential(
            nn.GELU(),
            nn.Linear(time_emb_dim, dim)
        ) if exists(time_emb_dim) else None

        self.ds_conv = nn.Conv2d(dim, dim, 7, padding=3, groups=dim)

        self.net = nn.Sequential(
            LayerNorm(dim) if norm else nn.Identity(),
            nn.Conv2d(dim, dim_out * mult, 3, padding=1),
            nn.GELU(),
            nn.Conv2d(dim_out * mult, dim_out, 3, padding=1)
        )

        self.res_conv = nn.Conv2d(dim, dim_out, 1) if dim != dim_out else nn.Identity()

    def forward(self, x, time_emb=None):
        h = self.ds_conv(x)

        if exists(self.mlp):
            assert exists(time_emb), 'time emb must be passed in'
            condition = self.mlp(time_emb)
            h = h + rearrange(condition, 'b c -> b c 1 1')

        h = self.net(h)
        return h + self.res_conv(x)

class LinearAttention(nn.Module):
    def __init__(self, dim, heads=4, dim_head=32):
        super().__init__()
        self.scale = dim_head ** -0.5
        self.heads = heads
        hidden_dim = dim_head * heads
        self.to_qkv = nn.Conv2d(dim, hidden_dim * 3, 1, bias=False)
        self.to_out = nn.Conv2d(hidden_dim, dim, 1)

    def forward(self, x):
        b, c, h, w = x.shape
        qkv = self.to_qkv(x).chunk(3, dim=1)
        q, k, v = map(lambda t: rearrange(t, 'b (h c) x y -> b h c (x y)', h=self.heads), qkv)
        q = q * self.scale

        k = k.softmax(dim=-1)
        context = torch.einsum('b h d n, b h e n -> b h d e', k, v)

        out = torch.einsum('b h d e, b h d n -> b h e n', context, q)
        out = rearrange(out, 'b h c (x y) -> b (h c) x y', h=self.heads, x=h, y=w)
        return self.to_out(out)

class Unet(nn.Module):
    def __init__(
            self,
            dim,
            out_dim=None,
            dim_mults=(1, 2, 4, 8),
            channels=3,
            with_time_emb=True,
            residual=False
    ):
        super().__init__()
        self.channels = channels
        self.residual = residual
        print("Is Time embed used ? ", with_time_emb)

        dims = [channels, *map(lambda m: dim * m, dim_mults)]
        in_out = list(zip(dims[:-1], dims[1:]))

        if with_time_emb:
            time_dim = dim
            self.time_mlp = nn.Sequential(
                SinusoidalPosEmb(dim),
                nn.Linear(dim, dim * 4),
                nn.GELU(),
                nn.Linear(dim * 4, dim)
            )
        else:
            time_dim = None
            self.time_mlp = None

        self.downs = nn.ModuleList([])
        self.ups = nn.ModuleList([])
        num_resolutions = len(in_out)

        for ind, (dim_in, dim_out) in enumerate(in_out):
            is_last = ind >= (num_resolutions - 1)

            self.downs.append(nn.ModuleList([
                ConvNextBlock(dim_in, dim_out, time_emb_dim=time_dim, norm=ind != 0),
                ConvNextBlock(dim_out, dim_out, time_emb_dim=time_dim),
                Residual(PreNorm(dim_out, LinearAttention(dim_out))),
                Downsample(dim_out) if not is_last else nn.Identity()
            ]))

        mid_dim = dims[-1]
        self.mid_block1 = ConvNextBlock(mid_dim, mid_dim, time_emb_dim=time_dim)
        self.mid_attn = Residual(PreNorm(mid_dim, LinearAttention(mid_dim)))
        self.mid_block2 = ConvNextBlock(mid_dim, mid_dim, time_emb_dim=time_dim)

        for ind, (dim_in, dim_out) in enumerate(reversed(in_out[1:])):
            is_last = ind >= (num_resolutions - 1)

            self.ups.append(nn.ModuleList([
                ConvNextBlock(dim_out * 2, dim_in, time_emb_dim=time_dim),
                ConvNextBlock(dim_in, dim_in, time_emb_dim=time_dim),
                Residual(PreNorm(dim_in, LinearAttention(dim_in))),
                Upsample(dim_in) if not is_last else nn.Identity()
            ]))

        out_dim = default(out_dim, channels)
        self.final_conv = nn.Sequential(
            ConvNextBlock(dim, dim),
            nn.Conv2d(dim, out_dim, 1)
        )

    def forward(self, x, time):
        orig_x = x
        t = self.time_mlp(time) if exists(self.time_mlp) else None

        h = []

        for convnext, convnext2, attn, downsample in self.downs:
            x = convnext(x, t)
            x = convnext2(x, t)
            x = attn(x)
            h.append(x)
            x = downsample(x)

        x = self.mid_block1(x, t)
        x = self.mid_attn(x)
        x = self.mid_block2(x, t)

        for convnext, convnext2, attn, upsample in self.ups:
            x = torch.cat((x, h.pop()), dim=1)
            x = convnext(x, t)
            x = convnext2(x, t)
            x = attn(x)
            x = upsample(x)
        if self.residual:
            return self.final_conv(x) + orig_x

        return self.final_conv(x)

class GaussianDiffusion(nn.Module):
    def __init__(
            self,
            defade_fn,
            *,
            image_size,
            device_of_kernel,
            channels=3,
            timesteps=1000,
            loss_type='l1',
            start_fade_factor=0.1,
            fade_routine='Incremental',
            train_routine='Final',
            sampling_routine='default'
    ):
        super().__init__()
        self.channels = channels
        self.image_size = image_size
        self.defade_fn = defade_fn
        self.device_of_kernel = device_of_kernel

        self.num_timesteps = int(timesteps)
        self.loss_type = loss_type
        self.start_fade_factor = start_fade_factor
        self.fade_routine = fade_routine

        self.fade_factors = self.get_fade_factors()
        self.train_routine = train_routine
        self.sampling_routine = sampling_routine

    def get_fade_factors(self):
        fade_factors = []
        for i in range(self.num_timesteps):
            if self.fade_routine == 'Incremental':
                fade_factors.append(1 - self.start_fade_factor * (i + 1))
            elif self.fade_routine == 'Constant':
                fade_factors.append(1 - self.start_fade_factor)
            elif self.fade_routine == 'Spiral':
                A = np.arange(32 * 32).reshape(32, 32)
                spiral = to_spiral(A)
                k = spiral > i
                k = torch.tensor(k).float()
                fade_factors.append(k.cuda())
            elif self.fade_routine == 'Spiral_2':
                A = np.arange(32 * 32).reshape(32, 32)
                spiral = to_spiral(A)
                k = spiral > i
                k = torch.tensor(k).float()
                fade_factors.append(k.cuda())

        return fade_factors

    @torch.no_grad()
    def sample(self, batch_size=16, img=None, t=None):

        if t is None:
            t = self.num_timesteps
        for i in range(t):
            with torch.no_grad():
                img = self.fade_factors[i] * img

        if self.fade_routine == 'Spiral_2':
            new_mean = torch.rand((img.shape[0], 3))
            new_mean = new_mean.unsqueeze(2).repeat(1, 1, img.shape[2])
            new_mean = new_mean.unsqueeze(3).repeat(1, 1, 1, img.shape[3]).cuda()

        for i in range(t):
            with torch.no_grad():
                if self.fade_routine == 'Spiral_2':
                    img = self.fade_factors[i] * img + new_mean * (torch.ones_like(self.fade_factors[i]) - self.fade_factors[i])
                else:
                    img = self.fade_factors[i] * img

        xt = img
        direct_recons = None
        while t:
            step = torch.full((batch_size,), t - 1, dtype=torch.long).cuda()
            x = self.defade_fn(img, step)

            if "Final" in self.train_routine:
                if direct_recons is None:
                    direct_recons = x

                if self.sampling_routine == 'default':
                    for i in range(t - 1):
                        with torch.no_grad():
                            x = self.fade_factors[i] * x

                elif self.sampling_routine == 'x0_step_down':
                    x_times = x
                    x_times_sub_1 = x

                    for i in range(t):
                        with torch.no_grad():
                            x_times_sub_1 = x_times
                            x_times = self.fade_factors[i] * x_times

                    x = img - x_times + x_times_sub_1

                elif self.sampling_routine == 'x0_step_down_spiral_2_fix':
                    x_times = x
                    x_times_sub_1 = x

                    for i in range(t):
                        with torch.no_grad():
                            x_times_sub_1 = x_times
                            x_times = self.fade_factors[i] * x_times + new_mean * (
                                        torch.ones_like(self.fade_factors[i]) - self.fade_factors[i])

                    x = img - x_times + x_times_sub_1

                elif self.sampling_routine == 'x0_step_down_spiral_2_rand':
                    x_times = x
                    x_times_sub_1 = x

                    for i in range(t):
                        new_mean = torch.rand((img.shape[0], 3))
                        new_mean = new_mean.unsqueeze(2).repeat(1, 1, img.shape[2])
                        new_mean = new_mean.unsqueeze(3).repeat(1, 1, 1, img.shape[3]).cuda()

                        with torch.no_grad():
                            x_times_sub_1 = x_times
                            x_times = self.fade_factors[i] * x_times + new_mean * (
                                        torch.ones_like(self.fade_factors[i]) - self.fade_factors[i])

                    x = img - x_times + x_times_sub_1

            elif self.train_routine == 'Step':
                if direct_recons is None:
                    direct_recons = x

            elif self.train_routine == 'Gradient_norm':
                if direct_recons is None:
                    direct_recons = img - x
                x = img - x

            img = x
            t = t - 1

        return xt, direct_recons, img

    @torch.no_grad()
    def all_sample(self, batch_size=16, img=None, t=None, times=None):

        if t is None:
            t = self.num_timesteps
        if times is None:
            times = t

        if self.fade_routine == 'Spiral_2':
            new_mean = torch.rand((img.shape[0], 3))
            new_mean = new_mean.unsqueeze(2).repeat(1, 1, img.shape[2])
            new_mean = new_mean.unsqueeze(3).repeat(1, 1, 1, img.shape[3]).cuda()

        for i in range(t):
            with torch.no_grad():
                if self.fade_routine == 'Spiral_2':
                    img = self.fade_factors[i] * img + new_mean * (
                                torch.ones_like(self.fade_factors[i]) - self.fade_factors[i])
                else:
                    img = self.fade_factors[i] * img

        x0_list = []
        xt_list = []

        while times:
            step = torch.full((batch_size,), times - 1, dtype=torch.long).cuda()
            x = self.defade_fn(img, step)
            x0_list.append(x)

            if "Final" in self.train_routine:
                if self.sampling_routine == 'default':
                    print("Normal")

                    x_times_sub_1 = x
                    for i in range(times - 1):
                        with torch.no_grad():
                            x_times_sub_1 = self.fade_factors[i] * x_times_sub_1

                    x = x_times_sub_1

                elif self.sampling_routine == 'x0_step_down':
                    print("x0_step_down")

                    x_times = x
                    for i in range(times):
                        with torch.no_grad():
                            x_times = self.fade_factors[i] * x_times

                    x_times_sub_1 = x
                    for i in range(times - 1):
                        with torch.no_grad():
                            x_times_sub_1 = self.fade_factors[i] * x_times_sub_1

                    x = img - x_times + x_times_sub_1

                elif self.sampling_routine == 'x0_step_down_spiral_2_fix':
                    x_times = x
                    x_times_sub_1 = x

                    for i in range(times):
                        with torch.no_grad():
                            x_times_sub_1 = x_times
                            x_times = self.fade_factors[i] * x_times + new_mean * (
                                        torch.ones_like(self.fade_factors[i]) - self.fade_factors[i])

                    x = img - x_times + x_times_sub_1

                elif self.sampling_routine == 'x0_step_down_spiral_2_rand':
                    x_times = x
                    x_times_sub_1 = x

                    for i in range(times):
                        new_mean = torch.rand((img.shape[0], 3))
                        new_mean = new_mean.unsqueeze(2).repeat(1, 1, img.shape[2])
                        new_mean = new_mean.unsqueeze(3).repeat(1, 1, 1, img.shape[3]).cuda()

                        with torch.no_grad():
                            x_times_sub_1 = x_times
                            x_times = self.fade_factors[i] * x_times + new_mean * (
                                        torch.ones_like(self.fade_factors[i]) - self.fade_factors[i])

                    x = img + x_times_sub_1 - img #- x_times

                elif self.sampling_routine == 'no_time_embed':
                    x = x
                    for i in range(100):
                        with torch.no_grad():
                            x = self.fade_factors[i] * x

            elif self.train_routine == 'Gradient_norm':
                x = img - 0.1 * x
                for i in range(10):
                    with torch.no_grad():
                        x = self.fade_factors[i] * x

            img = x
            xt_list.append(img)
            times = times - 1

        return x0_list, xt_list

    def q_sample(self, x_start, t):

        if self.fade_routine == 'Spiral':
            choose_fade = []
            for img_index in range(t.shape[0]):
                choose_fade.append(x_start[img_index,:] * self.fade_factors[t[img_index]] )

            choose_fade = torch.stack(choose_fade)
            return choose_fade

        elif self.fade_routine == 'Spiral_2':

            choose_fade = []
            for img_index in range(t.shape[0]):
                new_mean = torch.rand((1, 3))
                new_mean = new_mean.unsqueeze(2).repeat(1, 1, x_start.shape[2])
                new_mean = new_mean.unsqueeze(3).repeat(1, 1, 1, x_start.shape[3]).cuda()

                cf = x_start[img_index,:] * self.fade_factors[t[img_index]] + new_mean * (torch.ones_like(self.fade_factors[t[img_index]]) - self.fade_factors[t[img_index]])
                choose_fade.append(cf[0,:])

            choose_fade = torch.stack(choose_fade)
            return choose_fade

        else:
            max_iters = torch.max(t)
            all_fades = []
            x = x_start
            for i in range(max_iters + 1):
                with torch.no_grad():
                    x = self.fade_factors[i] * x
                    all_fades.append(x)

            all_fades = torch.stack(all_fades)

            choose_fade = []
            for step in range(t.shape[0]):
                if step != -1:
                    choose_fade.append(all_fades[t[step], step])
                else:
                    choose_fade.append(x_start[step])

            choose_fade = torch.stack(choose_fade)
            return choose_fade

    def p_losses(self, x_start, t):
        if self.train_routine == 'Final':
            x_fade = self.q_sample(x_start=x_start, t=t)
            x_recon = self.defade_fn(x_fade, t)

            if self.loss_type == 'l1':
                loss = (x_start - x_recon).abs().mean()
            elif self.loss_type == 'l2':
                loss = F.mse_loss(x_start, x_recon)
            else:
                raise NotImplementedError()

        elif self.train_routine == 'Gradient_norm':
            x_fade = self.q_sample(x_start=x_start, t=t)
            grad_pred = self.defade_fn(x_fade, t)
            gradient = (x_fade - x_start)
            norm = LA.norm(gradient, dim=(1, 2, 3), keepdim=True)
            gradient_norm = gradient / (norm + 1e-5)

            if self.loss_type == 'l1':
                loss = (gradient_norm - grad_pred).abs().mean()
            elif self.loss_type == 'l2':
                loss = F.mse_loss(gradient_norm, grad_pred)
            else:
                raise NotImplementedError()

        elif self.train_routine == 'Step':
            x_fade = self.q_sample(x_start=x_start, t=t)
            x_fade_sub = self.q_sample(x_start=x_start, t=t - 1)
            x_blur_sub_pred = self.defade_fn(x_fade, t)

            if self.loss_type == 'l1':
                loss = (x_fade_sub - x_blur_sub_pred).abs().mean()
            elif self.loss_type == 'l2':
                loss = F.mse_loss(x_fade_sub, x_blur_sub_pred)
            else:
                raise NotImplementedError()

        return loss

    def forward(self, x, *args, **kwargs):
        b, c, h, w, device, img_size, = *x.shape, x.device, self.image_size
        assert h == img_size and w == img_size, f'height and width of image must be {img_size}'
        t = torch.randint(0, self.num_timesteps, (b,), device=device).long()
        return self.p_losses(x, t, *args, **kwargs)

class Dataset(data.Dataset):
    def __init__(self, folder, image_size, exts=['jpg', 'jpeg', 'png']):
        super().__init__()
        self.folder = folder
        self.image_size = image_size
        self.paths = [p for ext in exts for p in Path(f'{folder}').glob(f'**/*.{ext}')]

        self.transform = transforms.Compose([
            transforms.Resize(image_size),
            transforms.CenterCrop(image_size),
            transforms.ToTensor(),
            transforms.Lambda(lambda t: (t * 2) - 1)
        ])

    def __len__(self):
        return len(self.paths)

    def __getitem__(self, index):
        path = self.paths[index]
        img = Image.open(path)
        return self.transform(img)

class Dataset_Cifar10(data.Dataset):
    def __init__(self, folder, image_size, exts=['jpg', 'jpeg', 'png']):
        super().__init__()
        self.folder = folder
        self.image_size = image_size
        self.paths = [p for ext in exts for p in Path(f'{folder}').glob(f'**/*.{ext}')]

        self.transform = transforms.Compose([
            transforms.RandomCrop(image_size, padding=4),
            transforms.Resize(image_size),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
            transforms.Lambda(lambda t: (t * 2) - 1)
        ])

    def __len__(self):
        return len(self.paths)

    def __getitem__(self, index):
        path = self.paths[index]
        img = Image.open(path)
        return self.transform(img)

class Trainer(object):
    def __init__(
            self,
            diffusion_model,
            folder,
            *,
            ema_decay=0.995,
            image_size=128,
            train_batch_size=32,
            train_lr=2e-5,
            train_num_steps=100000,
            gradient_accumulate_every=2,
            fp16=False,
            step_start_ema=2000,
            update_ema_every=10,
            save_and_sample_every=1000,
            results_folder='./results',
            load_path=None,
            dataset=None
    ):
        super().__init__()
        self.model = diffusion_model
        self.ema = EMA(ema_decay)
        self.ema_model = copy.deepcopy(self.model)
        self.update_ema_every = update_ema_every

        self.step_start_ema = step_start_ema
        self.save_and_sample_every = save_and_sample_every

        self.batch_size = train_batch_size
        self.image_size = diffusion_model.image_size
        self.gradient_accumulate_every = gradient_accumulate_every
        self.train_num_steps = train_num_steps

        if dataset == 'cifar10':
            self.ds = Dataset_Cifar10(folder, image_size)
        else:
            self.ds = Dataset(folder, image_size)
        self.dl = cycle(data.DataLoader(self.ds, batch_size=train_batch_size, shuffle=True, pin_memory=True))
        self.opt = Adam(diffusion_model.parameters(), lr=train_lr)

        self.step = 0

        assert not fp16 or fp16 and APEX_AVAILABLE, 'Apex must be installed in order for mixed precision training to be turned on'

        self.fp16 = fp16
        if fp16:
            (self.model, self.ema_model), self.opt = amp.initialize([self.model, self.ema_model], self.opt,
                                                                    opt_level='O1')

        self.results_folder = Path(results_folder)
        self.results_folder.mkdir(exist_ok=True)

        self.reset_parameters()

        if load_path is not None:
            self.load(load_path)

    def reset_parameters(self):
        self.ema_model.load_state_dict(self.model.state_dict())

    def step_ema(self):
        if self.step < self.step_start_ema:
            self.reset_parameters()
            return
        self.ema.update_model_average(self.ema_model, self.model)

    def save(self):
        data = {
            'step': self.step,
            'model': self.model.state_dict(),
            'ema': self.ema_model.state_dict()
        }
        torch.save(data, str(self.results_folder / f'model.pt'))

    def load(self, load_path):
        print("Loading : ", load_path)
        data = torch.load(load_path)

        self.step = data['step']
        self.model.load_state_dict(data['model'])
        self.ema_model.load_state_dict(data['ema'])

    def add_title(self, path, title):
        import cv2
        import numpy as np

        img1 = cv2.imread(path)
        black = [0, 0, 0]
        constant = cv2.copyMakeBorder(img1, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=black)
        height = 20
        violet = np.zeros((height, constant.shape[1], 3), np.uint8)
        violet[:] = (255, 0, 180)

        vcat = cv2.vconcat((violet, constant))

        font = cv2.FONT_HERSHEY_SIMPLEX

        cv2.putText(vcat, str(title), (violet.shape[1] // 2, height - 2), font, 0.5, (0, 0, 0), 1, 0)
        cv2.imwrite(path, vcat)

    def train(self):
        backwards = partial(loss_backwards, self.fp16)

        acc_loss = 0
        while self.step < self.train_num_steps:
            u_loss = 0
            for i in range(self.gradient_accumulate_every):
                data = next(self.dl).cuda()
                loss = self.model(data)
                print(f'{self.step}: {loss.item()}')
                u_loss += loss.item()
                backwards(loss / self.gradient_accumulate_every, self.opt)

            acc_loss = acc_loss + (u_loss / self.gradient_accumulate_every)

            self.opt.step()
            self.opt.zero_grad()

            if self.step % self.update_ema_every == 0:
                self.step_ema()

            if self.step != 0 and self.step % self.save_and_sample_every == 0:
                milestone = self.step // self.save_and_sample_every
                batches = self.batch_size
                og_img = next(self.dl).cuda()
                xt, direct_recons, all_images = self.ema_model.sample(batch_size=batches, faded_recon_sample=og_img)

                og_img = (og_img + 1) * 0.5
                utils.save_image(og_img, str(self.results_folder / f'sample-og-{milestone}.png'), nrow=6)

                all_images = (all_images + 1) * 0.5
                utils.save_image(all_images, str(self.results_folder / f'sample-recon-{milestone}.png'), nrow=6)

                direct_recons = (direct_recons + 1) * 0.5
                utils.save_image(direct_recons, str(self.results_folder / f'sample-direct_recons-{milestone}.png'),
                                 nrow=6)

                xt = (xt + 1) * 0.5
                utils.save_image(xt, str(self.results_folder / f'sample-xt-{milestone}.png'),
                                 nrow=6)

                acc_loss = acc_loss / (self.save_and_sample_every + 1)
                print(f'Mean of last {self.step}: {acc_loss}')
                acc_loss = 0

                self.save()

            self.step += 1

        print('training completed')

    def test_from_data(self, extra_path, s_times=None):
        batches = self.batch_size
        og_img = next(self.dl).cuda()
        x0_list, xt_list = self.ema_model.all_sample(batch_size=batches, faded_recon_sample=og_img, times=s_times)

        og_img = (og_img + 1) * 0.5
        utils.save_image(og_img, str(self.results_folder / f'og-{extra_path}.png'), nrow=6)

        import imageio
        frames_t = []
        frames_0 = []

        for i in range(len(x0_list)):
            print(i)

            x_0 = x0_list[i]
            x_0 = (x_0 + 1) * 0.5
            utils.save_image(x_0, str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'), nrow=6)
            self.add_title(str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'), str(i))
            frames_0.append(imageio.imread(str(self.results_folder / f'sample-{i}-{extra_path}-x0.png')))

            x_t = xt_list[i]
            all_images = (x_t + 1) * 0.5
            utils.save_image(all_images, str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'), nrow=6)
            self.add_title(str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'), str(i))
            frames_t.append(imageio.imread(str(self.results_folder / f'sample-{i}-{extra_path}-xt.png')))

        imageio.mimsave(str(self.results_folder / f'Gif-{extra_path}-x0.gif'), frames_0)
        imageio.mimsave(str(self.results_folder / f'Gif-{extra_path}-xt.gif'), frames_t)

    def test_with_mixup(self, extra_path):
        batches = self.batch_size
        og_img_1 = next(self.dl).cuda()
        og_img_2 = next(self.dl).cuda()
        og_img = (og_img_1 + og_img_2) / 2

        x0_list, xt_list = self.ema_model.all_sample(batch_size=batches, faded_recon_sample=og_img)

        og_img_1 = (og_img_1 + 1) * 0.5
        utils.save_image(og_img_1, str(self.results_folder / f'og1-{extra_path}.png'), nrow=6)

        og_img_2 = (og_img_2 + 1) * 0.5
        utils.save_image(og_img_2, str(self.results_folder / f'og2-{extra_path}.png'), nrow=6)

        og_img = (og_img + 1) * 0.5
        utils.save_image(og_img, str(self.results_folder / f'og-{extra_path}.png'), nrow=6)

        frames_t = []
        frames_0 = []

        for i in range(len(x0_list)):
            print(i)
            x_0 = x0_list[i]
            x_0 = (x_0 + 1) * 0.5
            utils.save_image(x_0, str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'), nrow=6)
            self.add_title(str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'), str(i))
            frames_0.append(Image.open(str(self.results_folder / f'sample-{i}-{extra_path}-x0.png')))

            x_t = xt_list[i]
            all_images = (x_t + 1) * 0.5
            utils.save_image(all_images, str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'), nrow=6)
            self.add_title(str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'), str(i))
            frames_t.append(Image.open(str(self.results_folder / f'sample-{i}-{extra_path}-xt.png')))

        frame_one = frames_0[0]
        frame_one.save(str(self.results_folder / f'Gif-{extra_path}-x0.gif'), format="GIF", append_images=frames_0,
                       save_all=True, duration=100, loop=0)

        frame_one = frames_t[0]
        frame_one.save(str(self.results_folder / f'Gif-{extra_path}-xt.gif'), format="GIF", append_images=frames_t,
                       save_all=True, duration=100, loop=0)

    def test_from_random(self, extra_path):
        batches = self.batch_size
        og_img = next(self.dl).cuda()
        og_img = og_img * 0.9  # torch.randn_like(og_img) + 0.1
        x0_list, xt_list = self.ema_model.all_sample(batch_size=batches, faded_recon_sample=og_img)

        og_img = (og_img + 1) * 0.5
        utils.save_image(og_img, str(self.results_folder / f'og-{extra_path}.png'), nrow=6)

        frames_t_names = []
        frames_0_names = []

        for i in range(len(x0_list)):
            print(i)

            x_0 = x0_list[i]
            x_0 = (x_0 + 1) * 0.5
            utils.save_image(x_0, str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'), nrow=6)
            self.add_title(str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'), str(i))
            frames_0_names.append(str(self.results_folder / f'sample-{i}-{extra_path}-x0.png'))

            x_t = xt_list[i]
            all_images = (x_t + 1) * 0.5
            utils.save_image(all_images, str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'), nrow=6)
            self.add_title(str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'), str(i))
            frames_t_names.append(str(self.results_folder / f'sample-{i}-{extra_path}-xt.png'))

        import imageio
        frames_0 = []
        frames_t = []
        for i in range(len(x0_list)):
            print(i)
            frames_0.append(imageio.imread(frames_0_names[i]))
            frames_t.append(imageio.imread(frames_t_names[i]))

        imageio.mimsave(str(self.results_folder / f'Gif-{extra_path}-x0.gif'), frames_0)
        imageio.mimsave(str(self.results_folder / f'Gif-{extra_path}-xt.gif'), frames_t)


'''
题目描述
特殊符号代替普通的计算方式比如 x#y = 2*x+y，x$y = x+3y， #优先级高于$。
比如输入 5#2$6 输出结果就是 30，因为先算 5#2 = 12，再算 12$6=30

示例 1
输入：5#2$6
输出：30

参考代码

'''
while 1:
    try:
        nums = input()

        stack = []
        i = 0
        j = 1
        while j < len(nums):
            if nums[j] == "#":
                stack.append(int("".join(nums[i:j])))
                stack.append(nums[j])
                i = j + 1
            elif nums[j] == "$":
                stack.append(int("".join(nums[i:j])))
                stack.append(nums[j])
                i = j + 1
            j += 1
        else:
            stack.append(int("".join(nums[i:j])))

        while "#" in stack:
            i = stack.index("#")
            stack[i-1] = 2 * stack[i-1]
            stack.pop(i)

        while "$" in stack:
            i = stack.index("$")
            stack[i+1] = 3 * stack[i+1]
            stack.pop(i)

        print(sum(stack))
    except Exception as e:
        break


from db.run_sql import run_sql
from models.item import Item
from repositories import categories_repository as cat_repo

def select(id):
    sql_string = "SELECT * FROM items WHERE id = %s"
    values = [int(id)]
    result = run_sql(sql_string,values)
    category = cat_repo.select(result[0]['cat_id'])
    item = Item(result[0]['name'], category, result[0]['id'])
    return item

def select_all():
    sql_string = "SELECT * FROM items ORDER BY cat_id"
    result = run_sql(sql_string)
    items = []
    for row in result:
        category = cat_repo.select(row['cat_id'])
        item = Item(row['name'], category, row['id'])
        items.append(item)
    return items

def add_new(item):
    sql_string = "INSERT INTO items (name, cat_id) VALUES (%s, %s) RETURNING *"
    values = [item.name, item.category.id]
    result = run_sql(sql_string, values)
    item.id = result[0]['id']
    return item

def save_item(item):
    sql_string = "UPDATE items SET (name, cat_id) = (%s, %s) WHERE id = %s"
    values = [item.name, item.category.id, item.id]
    run_sql(sql_string,values)

def delete_item(id):
    sql_string = "DELETE FROM items WHERE id = %s"
    values = [int(id)]
    run_sql(sql_string,values)

def select_cat_items(cat_id):
    sql_string = "SELECT * FROM items WHERE cat_id = %s"
    values = [cat_id]
    result = run_sql(sql_string,values)
    items = []
    for row in result:
        category = cat_repo.select(row['cat_id'])
        item = Item(row['name'], category, row['id'])
        items.append(item)
    return items


"""
:type  param_1: {String}
:rtype: string
"""
def last_word(text):
    if (text == ""):
        return ""

    new_str = ""
    text = text.strip()
    length = len(text)
    for i in range(length-1, 0, -1):
        if  (text[i] == " " or text[i] == "," or text[i] == "\t"):
            return new_str[::-1]
        else:
            new_str += text[i]

text = "    lorem, ipsum "
print(last_word(text))


import requests
import sqlite3
import matplotlib.pyplot as plt

# Download 1000 posts
url = 'https://jsonplaceholder.typicode.com/posts'
response = requests.get(url)
posts = response.json()[:1000]

# Count letters in the 'body' field
letter_counts = {}
for post in posts:
    body = post['body']
    for letter in body:
        if letter.isalpha():
            letter = letter.lower()
            letter_counts[letter] = letter_counts.get(letter, 0) + 1

# Generate a frequency histogram
letters = list(letter_counts.keys())
counts = list(letter_counts.values())

plt.bar(letters, counts)
plt.xlabel('Letters')
plt.ylabel('Frequency')
plt.title('Letter Frequency in Posts Body')
plt.show()

# Connect to SQLite database (creates a new one if not exists)
conn = sqlite3.connect('example.db')

# Create a cursor object to execute SQL queries
cursor = conn.cursor()

# Create a table to store post data if it doesn't exist
cursor.execute('''
    CREATE TABLE IF NOT EXISTS posts (
        id INTEGER PRIMARY KEY,
        userId INTEGER,
        title TEXT,
        body TEXT
    )
''')

# Commit the changes
conn.commit()

# Clear the 'posts' table
cursor.execute('DELETE FROM posts')

# Commit the changes
conn.commit()

# Insert posts into the table
for post in posts:
    cursor.execute('''
        INSERT INTO posts (userId, title, body)
        VALUES (?, ?, ?)
    ''', (post['userId'], post['title'], post['body']))

# Commit the changes
conn.commit()

# Validate if the number of rows matches the expected number of posts
cursor.execute('SELECT * FROM posts')
rows = cursor.fetchall()
expected_num_posts = len(posts)
if len(rows) == expected_num_posts:
    print(f"Successfully inserted {expected_num_posts} posts into the database.")
else:
    print(f"Error: Expected {expected_num_posts} posts, but found {len(rows)} posts in the database.")

# Close the connection
conn.close()


from django.urls import path,include
from . import views

urlpatterns = [
    path('', views.introcric,name='introcric'),
    path('IntroRPS/', views.introRPS,name='introRPS'),
    path('Registeration/', views.register,name='registeration'),
    path('Login/', views.login,name='Login'),
    path('Home/',views.user,name='home'),

    #cricket
    path('cricket/', views.toss,name='cricket'),
    path('batting/', views.battingprofile,name='batting'),
    path('balling/', views.ballingprofile,name='balling'),
    path('battingstart/', views.battingstart,name='battingstart'),   #playerbat first
    path('battingsecond/', views.battingsecond,name='battingsecond'),   #playerbat second
    path('ballingstart/', views.ballingstart,name='ballingstart'),    #opp bat first
    path('ballingsecond/', views.ballingsecond,name='ballingsecond'),    #opp bat second

    #Stone Paper Scissor
    path('RPS/', views.RPS,name='RPS'),
]