import re
import os
import time
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from sklearn.model_selection import train_test_split

from create_dataset.read_from_pkl import data_from_pkl
from create_dataset.read_from_json import data_from_json

drive_root = 'C:/TempFiles/math/'

# Attention
def scaled_dot_product_attention(q, k, v, mask):
    matmul_qk = tf.matmul(q, k, transpose_b=True)  # (..., seq_len_q, seq_len_k)

    # scale matmul_qk
    dk = tf.cast(tf.shape(k)[-1], tf.float32)
    scaled_attention_logits = matmul_qk / tf.math.sqrt(dk)

    # add the mask to the scaled tensor.
    if mask is not None:
        scaled_attention_logits += (mask * -1e9)

    # softmax is normalized on the last axis (seq_len_k) so that the scores
    # add up to 1.
    attention_weights = tf.nn.softmax(scaled_attention_logits, axis=-1)  # (..., seq_len_q, seq_len_k)

    output = tf.matmul(attention_weights, v)  # (..., seq_len_q, depth_v)

    return output, attention_weights

# Pointwise Feed forward network
def point_wise_feed_forward_network(d_model, dff):
    return tf.keras.Sequential([
        tf.keras.layers.Dense(dff, activation='relu'),  # (batch_size, seq_len, dff)
        tf.keras.layers.Dense(d_model)  # (batch_size, seq_len, d_model)
    ])

# We provide positional information about the data to the model,
# otherwise each sentence will be treated as Bag of Words
def get_angles(pos, i, d_model):
    angle_rates = 1 / np.power(10000, (2 * (i//2)) / np.float32(d_model))
    return pos * angle_rates

def positional_encoding(position, d_model):
    angle_rads = get_angles(np.arange(position)[:, np.newaxis],
                            np.arange(d_model)[np.newaxis, :],
                            d_model)

    # apply sin to even indices in the array; 2i
    angle_rads[:, 0::2] = np.sin(angle_rads[:, 0::2])

    # apply cos to odd indices in the array; 2i+1
    angle_rads[:, 1::2] = np.cos(angle_rads[:, 1::2])

    pos_encoding = angle_rads[np.newaxis, ...]

    return tf.cast(pos_encoding, dtype=tf.float32)

class MultiHeadAttention(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads):
        super(MultiHeadAttention, self).__init__()
        self.num_heads = num_heads
        self.d_model = d_model

        assert d_model % self.num_heads == 0

        self.depth = d_model // self.num_heads

        self.wq = tf.keras.layers.Dense(d_model)
        self.wk = tf.keras.layers.Dense(d_model)
        self.wv = tf.keras.layers.Dense(d_model)

        self.dense = tf.keras.layers.Dense(d_model)

    def split_heads(self, x, batch_size):
        """Split the last dimension into (num_heads, depth).
        Transpose the result such that the shape is (batch_size, num_heads, seq_len, depth)
        """
        x = tf.reshape(x, (batch_size, -1, self.num_heads, self.depth))
        return tf.transpose(x, perm=[0, 2, 1, 3])

    def call(self, v, k, q, mask):
        batch_size = tf.shape(q)[0]

        q = self.wq(q)  # (batch_size, seq_len, d_model)
        k = self.wk(k)  # (batch_size, seq_len, d_model)
        v = self.wv(v)  # (batch_size, seq_len, d_model)

        q = self.split_heads(q, batch_size)  # (batch_size, num_heads, seq_len_q, depth)
        k = self.split_heads(k, batch_size)  # (batch_size, num_heads, seq_len_k, depth)
        v = self.split_heads(v, batch_size)  # (batch_size, num_heads, seq_len_v, depth)

        # scaled_attention.shape == (batch_size, num_heads, seq_len_q, depth)
        # attention_weights.shape == (batch_size, num_heads, seq_len_q, seq_len_k)
        scaled_attention, attention_weights = scaled_dot_product_attention(
            q, k, v, mask)

        scaled_attention = tf.transpose(scaled_attention, perm=[0, 2, 1, 3])  # (batch_size, seq_len_q, num_heads, depth)

        concat_attention = tf.reshape(scaled_attention,
                                    (batch_size, -1, self.d_model))  # (batch_size, seq_len_q, d_model)

        output = self.dense(concat_attention)  # (batch_size, seq_len_q, d_model)

        return output, attention_weights

class EncoderLayer(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads, dff, rate=0.1):
        super(EncoderLayer, self).__init__()

        self.mha = MultiHeadAttention(d_model, num_heads)
        self.ffn = point_wise_feed_forward_network(d_model, dff)

        # normalize data per feature instead of batch
        self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
        self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6)

        self.dropout1 = tf.keras.layers.Dropout(rate)
        self.dropout2 = tf.keras.layers.Dropout(rate)

    def call(self, x, training, mask):
        # Multi-head attention layer
        attn_output, _ = self.mha(x, x, x, mask)
        attn_output = self.dropout1(attn_output, training=training)
        # add residual connection to avoid vanishing gradient problem
        out1 = self.layernorm1(x + attn_output)

        # Feedforward layer
        ffn_output = self.ffn(out1)
        ffn_output = self.dropout2(ffn_output, training=training)
        # add residual connection to avoid vanishing gradient problem
        out2 = self.layernorm2(out1 + ffn_output)
        return out2

class Encoder(tf.keras.layers.Layer):
    def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size,
                maximum_position_encoding, rate=0.1):
        super(Encoder, self).__init__()

        self.d_model = d_model
        self.num_layers = num_layers

        self.embedding = tf.keras.layers.Embedding(input_vocab_size, d_model)
        self.pos_encoding = positional_encoding(maximum_position_encoding,
                                                self.d_model)

        # Create encoder layers (count: num_layers)
        self.enc_layers = [EncoderLayer(d_model, num_heads, dff, rate)
                        for _ in range(num_layers)]

        self.dropout = tf.keras.layers.Dropout(rate)

    def call(self, x, training, mask):

        seq_len = tf.shape(x)[1]

        # adding embedding and position encoding.
        x = self.embedding(x)
        x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))
        x += self.pos_encoding[:, :seq_len, :]

        x = self.dropout(x, training=training)

        for i in range(self.num_layers):
            x = self.enc_layers[i](x, training, mask)

        return x

class DecoderLayer(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads, dff, rate=0.1):
        super(DecoderLayer, self).__init__()

        self.mha1 = MultiHeadAttention(d_model, num_heads)
        self.mha2 = MultiHeadAttention(d_model, num_heads)

        self.ffn = point_wise_feed_forward_network(d_model, dff)

        self.layernorm1 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
        self.layernorm2 = tf.keras.layers.LayerNormalization(epsilon=1e-6)
        self.layernorm3 = tf.keras.layers.LayerNormalization(epsilon=1e-6)

        self.dropout1 = tf.keras.layers.Dropout(rate)
        self.dropout2 = tf.keras.layers.Dropout(rate)
        self.dropout3 = tf.keras.layers.Dropout(rate)

    def call(self, x, enc_output, training,
            look_ahead_mask, padding_mask):

        # Masked multihead attention layer (padding + look-ahead)
        attn1, attn_weights_block1 = self.mha1(x, x, x, look_ahead_mask)
        attn1 = self.dropout1(attn1, training=training)
        # again add residual connection
        out1 = self.layernorm1(attn1 + x)

        # Masked multihead attention layer (only padding)
        # with input from encoder as Key and Value, and input from previous layer as Query
        attn2, attn_weights_block2 = self.mha2(
            enc_output, enc_output, out1, padding_mask)
        attn2 = self.dropout2(attn2, training=training)
        # again add residual connection
        out2 = self.layernorm2(attn2 + out1)

        # Feedforward layer
        ffn_output = self.ffn(out2)
        ffn_output = self.dropout3(ffn_output, training=training)
        # again add residual connection
        out3 = self.layernorm3(ffn_output + out2)
        return out3, attn_weights_block1, attn_weights_block2

class Decoder(tf.keras.layers.Layer):
    def __init__(self, num_layers, d_model, num_heads, dff, target_vocab_size,
                maximum_position_encoding, rate=0.1):
        super(Decoder, self).__init__()

        self.d_model = d_model
        self.num_layers = num_layers

        self.embedding = tf.keras.layers.Embedding(target_vocab_size, d_model)
        self.pos_encoding = positional_encoding(maximum_position_encoding, d_model)

        # Create decoder layers (count: num_layers)
        self.dec_layers = [DecoderLayer(d_model, num_heads, dff, rate)
                        for _ in range(num_layers)]
        self.dropout = tf.keras.layers.Dropout(rate)

    def call(self, x, enc_output, training,
            look_ahead_mask, padding_mask):

        seq_len = tf.shape(x)[1]
        attention_weights = {}

        x = self.embedding(x)  # (batch_size, target_seq_len, d_model)

        x *= tf.math.sqrt(tf.cast(self.d_model, tf.float32))

        x += self.pos_encoding[:,:seq_len,:]

        x = self.dropout(x, training=training)

        for i in range(self.num_layers):
            x, block1, block2 = self.dec_layers[i](x, enc_output, training,
                                                look_ahead_mask, padding_mask)

        # store attenion weights, they can be used to visualize while translating
        attention_weights['decoder_layer{}_block1'.format(i+1)] = block1
        attention_weights['decoder_layer{}_block2'.format(i+1)] = block2

        return x, attention_weights

class Transformer(tf.keras.Model):
    def __init__(self, num_layers, d_model, num_heads, dff, input_vocab_size,
                target_vocab_size, pe_input, pe_target, rate=0.1):
        super(Transformer, self).__init__()

        self.encoder = Encoder(num_layers, d_model, num_heads, dff,
                            input_vocab_size, pe_input, rate)

        self.decoder = Decoder(num_layers, d_model, num_heads, dff,
                            target_vocab_size, pe_target, rate)

        self.final_layer = tf.keras.layers.Dense(target_vocab_size)

    def call(self, inp, tar, training, enc_padding_mask,
            look_ahead_mask, dec_padding_mask):

        # Pass the input to the encoder
        enc_output = self.encoder(inp, training, enc_padding_mask)

        # Pass the encoder output to the decoder
        dec_output, attention_weights = self.decoder(
            tar, enc_output, training, look_ahead_mask, dec_padding_mask)

        # Pass the decoder output to the last linear layer
        final_output = self.final_layer(dec_output)

        return final_output, attention_weights

class CustomSchedule(tf.keras.optimizers.schedules.LearningRateSchedule):
    def __init__(self, d_model, warmup_steps=4000):
        super(CustomSchedule, self).__init__()

        self.d_model = d_model
        self.d_model = tf.cast(self.d_model, tf.float32)

        self.warmup_steps = warmup_steps

    def __call__(self, step):
        arg1 = tf.math.rsqrt(step)
        arg2 = step * (self.warmup_steps ** -1.5)

        return tf.math.rsqrt(self.d_model) * tf.math.minimum(arg1, arg2)

def transformer_data():

    ## Add a space between every character in the equation string.
    ##  Eg: 'x = 23 + 88' becomes 'x =  2 3 + 8 8'
    def convert_equation(eqn):
        elements = list(eqn)
        return ' '.join(elements)

    ## For the word problem, convert everything to lowercase, add spaces around all
    ## punctuations and digits, and remove any extra spaces.
    def preprocess_input(sentence):
        sentence = sentence.lower().strip()
        sentence = re.sub(r"([?.!,’])", r" \1 ", sentence)
        sentence = re.sub(r"([0-9])", r" \1 ", sentence)
        sentence = re.sub(r'[" "]+', " ", sentence)
        return sentence.rstrip().strip()

    ## For the equation, convert it to lowercase and remove extra spaces
    def preprocess_target(sentence):
        return sentence.lower().strip()

    ## Tokenize the given list of strings and return the tokenized output
    ## along with the fitted tokenizer.
    def tokenize(lang):
        lang_tokenizer = tf.keras.preprocessing.text.Tokenizer(filters='')
        lang_tokenizer.fit_on_texts(lang)
        tensor = lang_tokenizer.texts_to_sequences(lang)
        return tensor, lang_tokenizer

    ## Add integers for start and end tokens for input/target exps
    def append_start_end(x,last_int):
        l = []
        l.append(last_int+1)
        l.extend(x)
        l.append(last_int+2)
        return l

    data = data_from_pkl()
    input_exps = list(data['Question'].values)
    target_exps = list(data['Equation'].apply(lambda x: convert_equation(x)).values)

    ## Preprocessing and Tokenizing the Input and Target exps
    preprocessed_input_exps = list(map(preprocess_input, input_exps))
    preprocessed_target_exps = list(map(preprocess_target, target_exps))

    input_tensor, inp_lang_tokenizer = tokenize(preprocessed_input_exps)
    target_tensor, targ_lang_tokenizer = tokenize(preprocessed_target_exps)

    old_len = len(targ_lang_tokenizer.word_index)

    input_tensor_list = [append_start_end(i,len(inp_lang_tokenizer.word_index)) for i in input_tensor]
    target_tensor_list = [append_start_end(i,len(targ_lang_tokenizer.word_index)) for i in target_tensor]

    # Pad all sequences such that they are of equal length
    input_tensor = tf.keras.preprocessing.sequence.pad_sequences(input_tensor_list, padding='post')
    target_tensor = tf.keras.preprocessing.sequence.pad_sequences(target_tensor_list, padding='post')

    # Here we are increasing the vocabulary size of the target, by adding a
    # few extra vocabulary words (which will not actually be used) as otherwise the
    # small vocab size causes issues downstream in the network.
    keys = [str(i) for i in range(10,51)]
    for i,k in enumerate(keys):
        targ_lang_tokenizer.word_index[k]=len(targ_lang_tokenizer.word_index)+i+4

    # Creating training and validation tf datasets
    input_tensor_train, input_tensor_val, target_tensor_train, target_tensor_val = train_test_split(input_tensor,
                                                                                target_tensor,
                                                                                test_size=0.05,
                                                                                random_state=42)

    BUFFER_SIZE = len(input_tensor_train)
    BATCH_SIZE = 64
    dataset = tf.data.Dataset.from_tensor_slices((input_tensor_train, target_tensor_train)).shuffle(BUFFER_SIZE)
    dataset = dataset.batch(BATCH_SIZE, drop_remainder=True)
    num_layers = 4
    d_model = 128
    dff = 512
    num_heads = 8
    input_vocab_size = len(inp_lang_tokenizer.word_index)+3
    target_vocab_size = len(targ_lang_tokenizer.word_index)+3
    dropout_rate = 0.0

    # Positional Encoding

    # Masking

    # mask all elements are that not words (padding) so that it is not treated as input
    def create_padding_mask(seq):
        seq = tf.cast(tf.math.equal(seq, 0), tf.float32)

        # add extra dimensions to add the padding
        # to the attention logits.
        return seq[:, tf.newaxis, tf.newaxis, :]  # (batch_size, 1, 1, seq_len)

    def create_look_ahead_mask(size):
        mask = 1 - tf.linalg.band_part(tf.ones((size, size)), -1, 0)
        return mask

    dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)

    learning_rate = CustomSchedule(d_model)

    # Adam optimizer with a custom learning rate
    optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.9, beta_2=0.98,
                                        epsilon=1e-9)

    loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True, reduction='none')

    def loss_function(real, pred):
        # Apply a mask to paddings (0)
        mask = tf.math.logical_not(tf.math.equal(real, 0))
        loss_ = loss_object(real, pred)

        mask = tf.cast(mask, dtype=loss_.dtype)
        loss_ *= mask

        return tf.reduce_mean(loss_)

    train_loss = tf.keras.metrics.Mean(name='train_loss')
    train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy')

    transformer = Transformer(num_layers, d_model, num_heads, dff,
                          input_vocab_size, target_vocab_size,
                          pe_input=input_vocab_size,
                          pe_target=target_vocab_size,
                          rate=dropout_rate)

    def create_masks(inp, tar):
        # Encoder padding mask
        enc_padding_mask = create_padding_mask(inp)

        # Decoder padding mask
        dec_padding_mask = create_padding_mask(inp)

        # Look ahead mask (for hiding the rest of the sequence in the 1st decoder attention layer)
        look_ahead_mask = create_look_ahead_mask(tf.shape(tar)[1])
        dec_target_padding_mask = create_padding_mask(tar)
        combined_mask = tf.maximum(dec_target_padding_mask, look_ahead_mask)

        return enc_padding_mask, combined_mask, dec_padding_mask

    # checkpoints
    checkpoint_dir = os.path.join(drive_root, "checkpoints")

    if not os.path.exists(checkpoint_dir):
        os.makedirs(checkpoint_dir)

    checkpoint = tf.train.Checkpoint(transformer=transformer, optimizer=optimizer)
    ckpt_manager = tf.train.CheckpointManager(checkpoint, checkpoint_dir, max_to_keep=5)
    latest = ckpt_manager.latest_checkpoint

    if latest:
        epoch_num = int(latest.split('/')[-1].split('-')[-1])
        checkpoint.restore(latest)
        print ('Latest checkpoint restored!!')
    else:
        epoch_num = 0

    # Training
    EPOCHS = 5

    def train_step(inp, tar):
        tar_inp = tar[:, :-1]
        tar_real = tar[:, 1:]

        enc_padding_mask, combined_mask, dec_padding_mask = create_masks(inp, tar_inp)

        with tf.GradientTape() as tape:
            predictions, _ = transformer(inp, tar_inp,
                                        True,
                                        enc_padding_mask,
                                        combined_mask,
                                        dec_padding_mask)
            loss = loss_function(tar_real, predictions)

        gradients = tape.gradient(loss, transformer.trainable_variables)
        optimizer.apply_gradients(zip(gradients, transformer.trainable_variables))

        train_loss(loss)
        train_accuracy(tar_real, predictions)

    for epoch in range(epoch_num, EPOCHS):
        start = time.time()

        train_loss.reset_states()
        train_accuracy.reset_states()

        # inp -> question, tar -> equation
        for (batch, (inp, tar)) in enumerate(dataset):
            train_step(inp, tar)

            if batch % 50 == 0:
                print ('Epoch {} Batch {} Loss {:.4f} Accuracy {:.4f}'.format(
                    epoch + 1, batch, train_loss.result(), train_accuracy.result()))

        ckpt_save_path = ckpt_manager.save()
        print ('Saving checkpoint for epoch {} at {}'.format(epoch+1,
                                                                ckpt_save_path))

        print ('Epoch {} Loss {:.4f} Accuracy {:.4f}'.format(epoch + 1,
                                                        train_loss.result(),
                                                        train_accuracy.result()))

        print ('Time taken for 1 epoch: {} secs\n'.format(time.time() - start))

    def evaluate(inp_sentence):
        start_token = [len(inp_lang_tokenizer.word_index)+1]
        end_token = [len(inp_lang_tokenizer.word_index)+2]

        # inp sentence is the word problem, hence adding the start and end token
        inp_sentence = start_token + [inp_lang_tokenizer.word_index[i] for i in preprocess_input(inp_sentence).split(' ')]+end_token
        encoder_input = tf.expand_dims(inp_sentence, 0)

        # start with equation's start token
        decoder_input = [old_len+1]
        output = tf.expand_dims(decoder_input, 0)

        for i in range(MAX_LENGTH):
            enc_padding_mask, combined_mask, dec_padding_mask = create_masks(
                encoder_input, output)

            predictions, attention_weights = transformer(encoder_input,
                                                        output,
                                                        False,
                                                        enc_padding_mask,
                                                        combined_mask,
                                                        dec_padding_mask)

            # select the last word from the seq_len dimension
            predictions = predictions[: ,-1:, :]
            predicted_id = tf.cast(tf.argmax(predictions, axis=-1), tf.int32)

            # return the result if the predicted_id is equal to the end token
            if predicted_id == old_len+2:
                return tf.squeeze(output, axis=0), attention_weights

            # concatentate the predicted_id to the output which is given to the decoder
            # as its input.
            output = tf.concat([output, predicted_id], axis=-1)
        return tf.squeeze(output, axis=0), attention_weights

    def plot_attention_weights(attention, sentence, result, layer):
        fig = plt.figure(figsize=(16, 8))

        sentence = preprocess_input(sentence)

        attention = tf.squeeze(attention[layer], axis=0)

        for head in range(attention.shape[0]):
            ax = fig.add_subplot(2, 4, head+1)

            # plot the attention weights
            ax.matshow(attention[head][:-1, :], cmap='viridis')

            fontdict = {'fontsize': 10}

            ax.set_xticks(range(len(sentence.split(' '))+2))
            ax.set_yticks(range(len([targ_lang_tokenizer.index_word[i] for i in list(result.numpy())
                                if i < len(targ_lang_tokenizer.word_index) and i not in [0,old_len+1,old_len+2]])+3))

            ax.set_ylim(len([targ_lang_tokenizer.index_word[i] for i in list(result.numpy())
                                if i < len(targ_lang_tokenizer.word_index) and i not in [0,old_len+1,old_len+2]]), -0.5)

            ax.set_xticklabels(
                ['<start>']+sentence.split(' ')+['<end>'],
                fontdict=fontdict, rotation=90)

            ax.set_yticklabels([targ_lang_tokenizer.index_word[i] for i in list(result.numpy())
                                if i < len(targ_lang_tokenizer.word_index) and i not in [0,old_len+1,old_len+2]],
                            fontdict=fontdict)

            ax.set_xlabel('Head {}'.format(head+1))

        plt.tight_layout()
        plt.show()

    MAX_LENGTH = 40

    def translate(sentence, plot=''):
        result, attention_weights = evaluate(sentence)
        # print('result',list(result.numpy()))

        # use the result tokens to convert prediction into a list of characters
        # (not inclusing padding, start and end tokens)
        predicted_sentence = [targ_lang_tokenizer.index_word[i] for i in list(result.numpy()) if (i < len(targ_lang_tokenizer.word_index) and i not in [0,46,47])]

        print('Input: {}'.format(sentence))
        print('Predicted translation: {}'.format(' '.join(predicted_sentence)))

        if plot:
            plot_attention_weights(attention_weights, sentence, result, plot)

    def evaluate_results(inp_sentence):
        start_token = [len(inp_lang_tokenizer.word_index)+1]
        end_token = [len(inp_lang_tokenizer.word_index)+2]

        # inp sentence is the word problem, hence adding the start and end token
        inp_sentence = start_token + list(inp_sentence.numpy()[0]) + end_token

        encoder_input = tf.expand_dims(inp_sentence, 0)

        decoder_input = [old_len+1]
        output = tf.expand_dims(decoder_input, 0)

        for i in range(MAX_LENGTH):
            enc_padding_mask, combined_mask, dec_padding_mask = create_masks(
                encoder_input, output)

            # predictions.shape == (batch_size, seq_len, vocab_size)
            predictions, attention_weights = transformer(encoder_input,
                                                        output,
                                                        False,
                                                        enc_padding_mask,
                                                        combined_mask,
                                                        dec_padding_mask)

            # select the last word from the seq_len dimension
            predictions = predictions[: ,-1:, :]  # (batch_size, 1, vocab_size)

            predicted_id = tf.cast(tf.argmax(predictions, axis=-1), tf.int32)

            # return the result if the predicted_id is equal to the end token
            if predicted_id == old_len+2:
                return tf.squeeze(output, axis=0), attention_weights

            # concatentate the predicted_id to the output which is given to the decoder
            # as its input.
            output = tf.concat([output, predicted_id], axis=-1)

        return tf.squeeze(output, axis=0), attention_weights

    dataset_val = tf.data.Dataset.from_tensor_slices((input_tensor_val, target_tensor_val)).shuffle(BUFFER_SIZE)
    dataset_val = dataset_val.batch(1, drop_remainder=True)
    y_true = []
    y_pred = []
    acc_cnt = 0

    a = 0
    for (inp_val_batch, target_val_batch) in iter(dataset_val):
        a += 1
        if a % 10 == 0:
            print(a)
            print("Accuracy count: ",acc_cnt)
            print('------------------')
        target_sentence = ''
        for i in target_val_batch.numpy()[0]:
            if i not in [0,old_len+1,old_len+2]:
                target_sentence += (targ_lang_tokenizer.index_word[i] + ' ')

        y_true.append([target_sentence.split(' ')[:-1]])

        result, _ = evaluate_results(inp_val_batch)
        predicted_sentence = [targ_lang_tokenizer.index_word[i] for i in list(result.numpy()) if (i < len(targ_lang_tokenizer.word_index) and i not in [0,old_len+1,old_len+2])]
        y_pred.append(predicted_sentence)

        if target_sentence.split(' ')[:-1] == predicted_sentence:
            acc_cnt += 1


from collections import OrderedDict
from typing import Dict, List, Tuple, Set

from bulk_update.manager import BulkUpdateManager
from django.conf import settings
from django.db import models
from django.db.models.query import QuerySet

from django_mysql.models import Model as MySqlModel, SetCharField

from util.mathutils import solve_linear_least_squares, create_matrix, create_2d_vector

class Team(MySqlModel):
    """
    Attributes:

    :attr id: Unique team id, always equal to the team_number.
    :attr active_years {@set[int]}: A set of years that the team has been active (in commission, not participated)
    :attr website {@string}: URL for the team website
    :attr team_number: FRC assigned team number
    :attr name: Long FRC Team Name (note, this can be VERY long, short_name or nickname is recommended)
    :attr short_name: Short FRC Team Name (often the more wel
    :attr nickname: Team Nickname, e.g. Shaker Robotics or Cheesy Poofs
    :attr key: Most specific team name, simply frc#### where #### is the team number
    """

    active_years = SetCharField(base_field=models.IntegerField(), max_length=255, default=set())

    website = models.URLField(null=True)
    name = models.TextField(null=True)  # longer name

    locality = models.CharField(max_length=50, null=True)  # e.g. city
    region = models.CharField(max_length=50, null=True)  # e.g. state, province
    country_name = models.CharField(max_length=50, null=True)
    location = models.CharField(max_length=150, null=True)  # full city + state + country

    team_number = models.PositiveSmallIntegerField(db_index=True)
    key = models.CharField(max_length=8)  # e.g. frc2791
    nickname = models.CharField(max_length=100, null=True)  # shorter name
    rookie_year = models.PositiveSmallIntegerField(null=True)
    motto = models.TextField(null=True)

    # TrueSkill distribution, which is a model of player skill which assumes a Gaussian distribution with
    # an initial estimate (mean mu, player is assumed to be of average skill) and confidence (standard deviation sigma).
    elo_mu = models.FloatField(default=settings.DEFAULT_MU)
    elo_sigma = models.FloatField(default=settings.DEFAULT_SIGMA)

    objects = BulkUpdateManager()

    # Stats that are too expensive to compute on the fly
    # see util.management.commands.update
    # Yes, it is trivially easy to get some of these through basic querysets. However, this allows us for a much
    # faster lookup at the expense of a very small amount of database space.
    active_event_winstreak = models.PositiveSmallIntegerField(default=0)
    longest_event_winstreak = models.PositiveSmallIntegerField(default=0)
    event_wins_count = models.PositiveSmallIntegerField(default=0)
    event_attended_count = models.PositiveSmallIntegerField(default=0)
    event_winrate = models.FloatField(default=0.0)

    match_wins_count = models.PositiveSmallIntegerField(default=0)
    match_losses_count = models.PositiveSmallIntegerField(default=0)
    match_ties_count = models.PositiveSmallIntegerField(default=0)
    match_winrate = models.FloatField(default=0.0)

    awards_count = models.PositiveSmallIntegerField(default=0)
    blue_banners_count = models.PositiveSmallIntegerField(default=0)

    def __str__(self):
        return "{0} ({1})".format(self.nickname, self.team_number)

    def get_matches(self, year=None) -> QuerySet:

        if year is None:
            return Match.objects.filter(alliances__teams__team_number=self.team_number)
        else:
            return Match.objects.filter(event__year=year).filter(alliances__teams__team_number=self.team_number)

    def get_wins(self, year=None) -> QuerySet:
        matches = Match.objects.prefetch_related('winner__teams')
        if year is None:
            return matches.filter(winner__teams__team_number=self.team_number)
        else:
            matches.select_related('event')
            return matches.filter(event__year=year).filter(winner__teams__team_number=self.team_number)

    def get_losses(self, year=None) -> QuerySet:
        matches = Match.objects.prefetch_related('alliances__teams').select_related('winner')
        if year is None:
            return matches.filter(alliances__teams__team_number=self.team_number).exclude(
                winner__teams__team_number=self.team_number).exclude(winner__isnull=True)
        else:
            matches.select_related('event')
            return matches.filter(event__year=year).filter(
                alliances__teams__team_number=self.team_number).exclude(
                winner__teams__team_number=self.team_number).exclude(winner__isnull=True)

    def get_ties(self, year=None) -> QuerySet:
        matches = Match.objects.prefetch_related('alliances__teams').select_related('winner')
        if year is None:
            return matches.filter(alliances__teams__team_number=self.team_number, winner__isnull=True)
        else:
            matches.select_related('event')
            return matches.filter(event__year=year) \
                .filter(alliances__teams__team_number=self.team_number, winner__isnull=True)

    def get_record(self) -> str:
        return "{0}-{1}-{2}".format(self.match_wins_count, self.match_losses_count, self.match_ties_count)

    def get_winrate(self) -> float:
        return self.match_winrate * 100.0

    def get_elo_standing(self) -> int:
        return Team.objects.filter(elo_mu__gte=self.elo_mu).count()

    def get_awards(self, year=None) -> QuerySet:
        if year is None:
            return Award.objects.filter(recipients=self)
        else:
            return Award.objects.filter(recipients=self, year=year)

    def count_awards_old(self) -> QuerySet:
        return Team.objects.filter(team_number=self.team_number).values_list('award__name'). \
            annotate(count=models.Count('award__award_type')).order_by('-count')

    def count_awards(self) -> Dict[str, List['Event']]:
        awards = {}
        award_types = set(self.award_set.values_list('award_type', flat=True).all())
        types_to_names = {t: Award.choice_to_display(t) for t in award_types}

        # get_events = lambda award_t: Event.objects.filter(award__award_type=award_t, award__recipients=self).values_list(flat=True)
        # This is great if the if statement in the below loop is not required...
        # awards = {types_to_names[t]: get_events(t) for t in award_types}

        for award_t in award_types:
            award = types_to_names[award_t]
            if award not in awards:
                awards[award] = Event.objects.filter(award__award_type=award_t, award__recipients=self).all()

        awards = {k: v for k, v in awards.items() if len(v) > 0}
        return OrderedDict(sorted(awards.items(), key=lambda entry: -len(entry[1])))

    def get_max_opr(self) -> float:
        return self.rankingmodel_set.order_by('-tba_opr').first().tba_opr

    def to_dict(self) -> dict:
        return dict((name, getattr(self, name)) for name in self.__dict__ if not name.startswith('_'))

class Alliance(MySqlModel):
    teams = models.ManyToManyField(Team)

    elo_mu = models.FloatField(default=settings.DEFAULT_MU)
    elo_sigma = models.FloatField(default=settings.DEFAULT_SIGMA)

    objects = BulkUpdateManager()

    def __str__(self):
        return "{0}".format(self.teams.all())

    def get_elo_standing(self) -> int:
        return Alliance.objects.filter(elo_mu__gte=self.elo_mu).count()

    def get_wins(self) -> QuerySet:
        return self.match_set.filter(winner=self)

    def get_losses(self) -> QuerySet:
        return self.match_set.exclude(winner=self).exclude(winner__isnull=True)

    def get_ties(self) -> QuerySet:
        return self.match_set.exclude(winner=self).filter(winner__isnull=True)

    def get_record(self) -> str:
        return "{0}-{1}-{2}".format(self.get_wins().count(), self.get_losses().count(), self.get_ties().count())

class Event(MySqlModel):
    """

    :attr id: Unique database id
    :attr key: Unique event key, often of the form ###w where #### is the year and w is the event code
    :attr name: Full event name (e.g. Finger Lakes Regional)
    :attr short_name: Shortened event name (e.g. Finger Lakes)
    :attr event_code: Unique event code (e.g. iri for Indiana Robotics Invitational)
    """
    key = models.CharField(max_length=10, unique=True)  # e.g. 2016cmp
    name = models.CharField(max_length=100)  # e.g. Finger Lakes Regional
    short_name = models.CharField(null=True, max_length=50)  # e.g. Finger Lakes
    event_code = models.CharField(max_length=7)  # e.g. cmp

    """https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/event_type.py"""
    event_type_choices = (
        (0, 'Regional'),
        (1, 'District'),
        (2, 'District Championship'),
        (3, 'Championship Division'),
        (4, 'Championship Finals'),
        (99, 'Offseason'),
        (100, 'Preseason'),
        (-1, 'Unlabeled')
    )
    event_type = models.SmallIntegerField(choices=event_type_choices, null=True)

    """https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/district_type.py#L6"""
    event_district_choices = (
        (0, 'No District'),
        (1, 'Michigan'),
        (2, 'Mid-Atlantic'),
        (3, 'New England'),
        (4, 'Pacific Northwest'),
        (5, 'Indiana'),
        (6, 'Chesapeake'),
        (7, 'North Carolina'),
        (8, 'Georgia'),
    )
    event_district = models.SmallIntegerField(choices=event_district_choices, null=True)

    year = models.PositiveSmallIntegerField()
    location = models.CharField(max_length=50, null=True)
    venue_address = models.TextField(null=True)
    timezone = models.CharField(max_length=35, null=True)
    website = models.URLField(null=True)
    official = models.BooleanField()
    teams = models.ManyToManyField(Team)
    alliances = models.ManyToManyField(Alliance)
    end_date = models.DateField(null=True)
    winning_alliance = models.ForeignKey(Alliance, related_name='winning_alliance', null=True)

    # webcast = my_webcast_model(), parse JSON data to model fields
    # district_points = my_district_points_model(), parse JSON data to model fields

    def __str__(self):
        return "{0}".format(self.key)

    def __eq__(self, other):
        if isinstance(other, Event):
            return self.key == other.key
        else:
            return False

    def has_f3_match(self) -> bool:
        """

        Returns:
            true if the event's finals set went to three games, false otherwise

        """
        return Match.objects.select_related('event') \
            .filter(comp_level__exact='f', match_number__exact=3, event__key__exact=self.key).exists()

    def get_oprs(self) -> Tuple[Tuple[Team, float]]:
        """
        Gets the OPRs for all teams participating in this event, these are returned as (team, opr) tuples.

        Done using the method of linear least squares.
        :return: Tuple of (Team, OPR) pairs
        """

        matches = Match.objects.prefetch_related('red_alliance__teams', 'blue_alliance__teams') \
            .select_related('scoring_model').filter(event=self, comp_level='qm')
        teams = set(Team.objects.filter(event=self).all())      # type: Set[Team]

        # Populate Score Vector
        s_vector = []
        for m in matches:
            s_vector.append(m.scoring_model.red_total_score)
            s_vector.append(m.scoring_model.blue_total_score)

        # Populate Match Matrix, each row consisting of 3 teams, all from either Blue or Red alliance
        m_row_array = []
        if self.year == 2016:
            from TBAW.models import RankingModel2016
            rms = RankingModel2016.objects.select_related('team') \
                .filter(event=self) \
                .annotate(total_contribution=models.F('goals_points') + models.F('auton_points')) \
                .order_by('-total_contribution')

        for match in matches:
            red_teams = set(match.red_alliance.teams.all())
            blue_teams = set(match.blue_alliance.teams.all())

            if self.year == 2016:
                max_contribution = rms.first().total_contribution
                ratios = [rms.get(team=team).c / max_contribution for team in teams]
                contribution_ratios = zip(ratios, teams)
            else:
                contribution_ratios = zip([1.0] * len(teams), teams)

            red_row = [cont_ratio if team in red_teams else 0 for cont_ratio, team in contribution_ratios]
            blue_row = [cont_ratio if team in blue_teams else 0 for cont_ratio, team in contribution_ratios]

            m_row_array.append(red_row)
            m_row_array.append(blue_row)

        # (Eq. 1): [A][OPR] = [SCORE]
        # (Eq. 2): [A]^T[A][OPR] = [A]^T[SCORE], from (Eq. 1)
        #          [P][OPR] = [S], [P] = [A]^T[A] and [S] = [A]^T[SCORE]
        # (Eq. 3): [L][L]^T[OPR] = [S], where [L] is the lower triangular matrix from Cholesky Decomposition of [P]
        # (Eq. 4): [L][y] = [S], [y] = [L]^T[OPR]
        #          Using Forward Substitution to solve for vector [y]
        #
        # [y] is then known, [y] = [L]^T[OPR], [L]^T is an upper triangular matrix,
        # backwards substitute to solve for OPR.
        oprs = solve_linear_least_squares(create_matrix(m_row_array), create_2d_vector(s_vector))
        team_oprs = zip(teams, oprs)    # type: List[Tuple[Team, float]]
        return tuple((team, opr.item(0)) for team, opr in team_oprs)

    def compare_oprs(self):
        from TBAW.models import RankingModel2016
        rms = [rm.team for rm in RankingModel2016.objects.filter(event=self).order_by('-tba_opr')]
        oth = [res[0] for res in self.get_oprs()]

        for i, (tba, frs) in enumerate(zip(rms, oth)):
            print('{0}.) {1},{0}.) {2}'.format(i + 1, tba, frs))

class Match(MySqlModel):
    key = models.CharField(max_length=20,
                           unique=True)  # yyyy{EVENT_CODE}_{COMP_LEVEL}m{MATCH_NUMBER}, e.g. 2016nyro_f1m2
    comp_level = models.CharField(max_length=6)  # e.g. qm, ef, qf, sf, f
    set_number = models.CharField(null=True, max_length=20)  # in 2016nyro_qf3m2, the set number is 3

    match_number = models.CharField(max_length=20)  # e.g. 2016nyro_qm20
    alliances = models.ManyToManyField(Alliance)
    # videos = my_videos_model, parse JSON data to model fields
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    # time_string = models.CharField(max_length=25)
    # time = models.DateTimeField(), parse UNIX timestamp to DatetimeField

    blue_alliance = models.ForeignKey(Alliance, null=True, related_name='blue_alliance')
    red_alliance = models.ForeignKey(Alliance, null=True, related_name='red_alliance')
    winner = models.ForeignKey(Alliance, null=True, related_name='winner')
    scoring_model = models.ForeignKey('TBAW.ScoringModel', null=True)

    objects = BulkUpdateManager()

    def __str__(self):
        return "{0}".format(self.key)

class Award(MySqlModel):
    name = models.CharField(max_length=150)

    # https://github.com/the-blue-alliance/the-blue-alliance/blob/master/consts/award_type.py#L15
    award_type_choices = (
        (0, "Chairman's"),
        (1, "Winner"),
        (2, "Finalist"),
        (3, "Woodie Flowers"),
        (4, "Dean's List"),
        (5, "Volunteer"),
        (6, "Founders"),
        (7, "Bart Kamen Memorial"),
        (8, "Make It Loud"),
        (9, "Engineering Inspiration"),
        (10, "Rookie All Star"),
        (11, "Gracious Professionalism"),
        (12, "Coopertition"),
        (13, "Judges"),
        (14, "Highest Rookie Seed"),
        (15, "Rookie Inspiration"),
        (16, "Industrial Design"),
        (17, "Quality"),
        (18, "Safety"),
        (19, "Sportsmanship"),
        (20, "Creativity"),
        (21, "Engineering Excellence"),
        (22, "Entrepreneurship"),
        (23, "Excellence in Design"),
        (24, "Excellence in Design (CAD)"),
        (25, "Excellence in Design (Animation)"),
        (26, "Driving Tomorrow's Technology"),
        (27, "Imagery"),
        (28, "Media and Technology"),
        (29, "Innovation in Control"),
        (30, "Spirit"),
        (31, "Website"),
        (32, "Visualization"),
        (33, "Autodesk Inventor"),
        (34, "Future Innovator"),
        (35, "Recognition of Extraordinary Service"),
        (36, "Outstanding Cart"),
        (37, "WSU Aim Higher"),
        (38, "Leadership in Control"),
        (39, "Number 1 Seed"),
        (40, "Incredible Play"),
        (41, "People's Choice Animation"),
        (42, "Rising Star Visualization"),
        (43, "Best Offensive Round"),
        (44, "Best Play of the Day"),
        (45, "Featherweight in the Finals"),
        (46, "Most Photogenic"),
        (47, "Outstanding Defense"),
        (48, "Power to Simplify"),
        (49, "Against All Odds"),
        (50, "Rising Star"),
        (51, "Chairman's Honorable Mention"),
        (52, "Content Communication Honorable Mention"),
        (53, "Technical Execution Honorable Mention"),
        (54, "Realization"),
        (55, "Realization Honorable Mention"),
        (56, "Design Your Future"),
        (57, "Design Your Future Honorable Mention"),
        (58, "Special Recognition Character Animation"),
        (59, "High Score"),
        (60, "Teacher Pioneer"),
        (61, "Best Craftsmanship"),
        (62, "Best Defensive Match"),
        (63, "Play of the Day"),
        (64, "Programming"),
        (65, "Professionalism"),
        (66, "Golden Corndog"),
        (67, "Most Improved Team"),
        (68, "Wildcard"),
    )

    blue_banner_choices = (
        (0, "Chairman's"),
        (1, "Winner"),
        (9, "Engineering Inspiration"),
    )

    non_district_point_choices = (
        (1, "Winner"),
        (2, "Finalist"),
        (3, "Woodie Flowers"),
        (4, "Dean's List"),
        (5, "Volunteer"),
        (14, "Highest Rookie Seed"),
    )

    award_type = models.PositiveSmallIntegerField(choices=award_type_choices)
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    recipients = models.ManyToManyField(Team)
    year = models.PositiveSmallIntegerField()

    def __str__(self):
        return "{0} - {1} ({2})".format(self.recipients.all(), self.name, self.event)

    @classmethod
    def choice_to_display(cls, choice):
        """

        Args:
            choice: a number inside award_type_choices

        Returns:
            The string associated with the choice. Works the same as some_award.get_award_type_display() but is a
            class method.

        """
        for c in Award.award_type_choices:
            if c[0] == choice:
                return c[1]

        return None

class Robot(MySqlModel):
    key = models.CharField(max_length=13, null=True)  # e.g. frc2791_2016
    team = models.ForeignKey(Team, null=True)
    year = models.PositiveSmallIntegerField(null=True)
    name = models.CharField(max_length=100, null=True)

class AllianceAppearance(MySqlModel):
    alliance = models.ForeignKey(Alliance, null=True)
    event = models.ForeignKey(Event, null=True)

    captain = models.ForeignKey(Team, related_name='captain', null=True)
    first_pick = models.ForeignKey(Team, related_name='first_pick', null=True)
    second_pick = models.ForeignKey(Team, related_name='second_pick', null=True)
    backup = models.ForeignKey(Team, related_name='backup', null=True)

    seed = models.PositiveSmallIntegerField(null=True)
    elo_mu_pre = models.FloatField(null=True)
    elo_mu_post = models.FloatField(null=True)
    elo_sigma_pre = models.FloatField(null=True)
    elo_sigma_post = models.FloatField(null=True)

    objects = BulkUpdateManager()


import cv2
import cvzone

# Initialize camera capture
cap = cv2.VideoCapture(2)

# Start an infinite loop to continually capture frames
while True:
    # Read image frame from camera
    success, img = cap.read()

    # Convert the image to grayscale
    imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Resize the image to be smaller (0.1x of original size)
    imgSmall = cv2.resize(img, (0, 0), None, 0.1, 0.1)

    # Resize the image to be larger (3x of original size)
    imgBig = cv2.resize(img, (0, 0), None, 3, 3)

    # Apply Canny edge detection on the grayscale image
    imgCanny = cv2.Canny(imgGray, 50, 150)

    # Convert the image to HSV color space
    imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

    # Create a list of all processed images
    imgList = [img, imgGray, imgCanny, imgSmall, imgBig, imgHSV]

    # Stack the images together using cvzone's stackImages function
    stackedImg = cvzone.stackImages(imgList, 3, 0.7)

    # Display the stacked images
    cv2.imshow("stackedImg", stackedImg)

    # Wait for 1 millisecond; this also allows for keyboard inputs
    cv2.waitKey(1)


import unittest
import mock
import logging
import os
import broadinstitute_psp.utils.setup_logger as setup_logger
import pour

# mock setup environment variables
API_BASE_URL= "http://API_URL"
environDict = {"API_KEY": "API_KEY",
               "API_URL":API_BASE_URL,
               "PANORAMA_USER": "test_user",
               "PANORAMA_AUTH":"test_auth"}

def get_environ_item(name):
    return environDict[name]

pour.os.environ = mock.MagicMock()
pour.os.environ.__getitem__.side_effect = get_environ_item

#set up s3 mocks
s3 = mock.Mock()
s3.Object = mock.Mock()
s3.Object.return_value.get = mock.MagicMock()

s3Dict = {"Body":True}
def s3_get_item(key):
    return s3Dict[key]
s3.Object.return_value.get.__getitem__.side_effect = s3_get_item
s3.Object.return_value.get.read = mock.Mock()

pour.boto3.resource = mock.Mock(return_value=s3)

class TestPour(unittest.TestCase):

    def test_get_panorama_request_and_parse(self):
        pour.json.loads = mock.Mock(return_value={"id":"test_id"})

        bucket_name = "test_bucket"
        current_gct_key = "psp/level4/test_plate_name_LVL4.gct"

        #happy path should return request_id
        request_id = pour.get_panorama_request_and_parse(s3, bucket_name, current_gct_key)
        self.assertEqual("test_id", request_id)

    def test_get_api_entry_from_proteomics_clue(self):
        pass

    # post_update_to_proteomics_clue fully tested in utils.test_lambda_utils

if __name__ == "__main__":
    setup_logger.setup(verbose=True)

    unittest.main()


def evaluate_post_fix(exp):
    stack = MyStack()
    for char in exp:
        if char.isdigit():
            stack.push(char)
        else:
            left = stack.pop()
            right = stack.pop()
            ''' Using Python's eval () method that takes a str expression,
            evaluates it and returns an integer '''
            stack.push(str(eval(right + char + left)))
    return int(float(stack.pop()))


from sales.models import DailySale
from stores.models import Store
from beers.models import Beer
from olmonopolet.stock import restock
from datetime import date
from django.core.exceptions import ObjectDoesNotExist

def get_daily_beer_sale(beer, store, current_stock, new_stock, stock_before_empty):
    """
    Get accumulated sales for a beer in a store, based on stock diff for today.
    Checks current sales for the day and adds stock diff to sales if new stock is less than current stock.
    Checks that new stock is different from stock before store was empty since this represent a bug in the VMP system where beers get stock=0 and then is reset.
    Returns negative sales when VMP has set stock to 0 and then reset to stock before zero.

    Parameters:
    Beer model instance:
    Store model instance:
    int: current stock in DB before updated with new stock
    int: new stock
    int: Last available product stock before store was empty

    Returns:
    int: Sum of daily sales in store for beer.
    """

    try:
        # Get current sales for today, if there are any
        sales_today = DailySale.objects.get(
            beer_id=beer, store_id=store, sales_day=date.today()
        )
        accumulated_daily_sale = sales_today.beers_sold
    except ObjectDoesNotExist as err:
        # First stock/sales update of each date will be processed here
        accumulated_daily_sale = 0

    if new_stock > current_stock and not restock.is_restocked(current_stock,new_stock, stock_before_empty):
        # Subtract sales that were falsly assigned due to VMP setting stock to 0 and then resetting stock
        # Accounting for any sales while stock was 0 by subtracting new_stock since this value is < stock_before_empty
        accumulated_daily_sale -= new_stock
    elif new_stock > current_stock:
        # Re-stock implies no additional sales
        pass
    elif new_stock <= current_stock:
        accumulated_daily_sale += current_stock - new_stock

    return accumulated_daily_sale


#!/usr/bin/python3

#
#   Created by Stephen Farnsworth
#

import sys

def solve_case(seed, pieces):

    while len(pieces):
        initial_size = len(pieces)
        for piece in pieces:
            #print 'Seed:\'' + seed + '\'\tPiece: \'' + piece + '\''
            #print 'checking \'' + seed[:len(piece) - 1] + '\' against \'' + piece[1:] + '\''
            # Check if the piece precedes our block
            if seed[:len(piece) - 1] == piece[1:]:
                #print '-------------------' + piece
                seed = piece[:1] + seed
                #print seed
                pieces.remove(piece)
                break

            #print 'checking \'' + seed[-len(piece) + 1:] + '\' against \'' + piece[:-1] + '\''
            # Check if the comes after our block
            if seed[-len(piece) + 1:] == piece[:-1]:
                #print '-------------------' + piece
                seed += piece[-1:]
                #print seed
                pieces.remove(piece)
                break

        if initial_size == len(pieces):
            #print 'Failed to glue'
            return False
    print(seed)
    return True

test_cases = open(sys.argv[1], 'r')
for line in test_cases:

    pieces = list(filter(None, line.strip('\n').split('|')))
    seed = pieces.pop(-1)
    #print 'Starting with ' + seed
    pieces_copy = pieces[:]
    while not solve_case(seed, pieces_copy):
        #print 'Trying ' + seed
        #print pieces
        pieces.insert(0, seed)
        seed = pieces.pop(-1)
        pieces_copy = pieces[:]


import cv2

def captureVideo(cap, writer):
    while True:
        ret,frame = cap.read()

        writer.write(frame)

        cv2.imshow('frame', frame)

        if cv2.waitKey(1) & 0xFF == 27:
            break

def recordVideo(inputCam):
    cap = cv2.VideoCapture(f'udpsrc port=5{inputCam}00 ! application/x-rtp, encoding-name=JPEG,payload=26 ! rtpjpegdepay ! jpegdec ! videoconvert ! appsink', cv2.CAP_GSTREAMER)
    # cap = cv2.VideoCapture(0)

    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    writer = cv2.VideoWriter('underwaterVideo.mp4', cv2.VideoWriter_fourcc(*'DIVX'), 20, (width,height))

    captureVideo(cap, writer)

    cap.release()
    writer.release()
    cv2.destroyAllWindows()


n = int(input())
ds = [
    list(map(int, input().split()))
    for _ in range(n)
]

ds = sorted([
    (x, x + l, l)
    for x, l in ds
], key=lambda a: (a[1], a[2]))

px = float('-inf')
ans = 0
for x, y, l in ds:
    if px <= x - l:
        px = y
        ans += 1
print(ans)


#coding:utf-8
from numpy import *
import matplotlib.pyplot as plt

class BPnet(object):
	def __init__(self):
		self.learningRate=0.1  #学习率
		self.learningRate_max=0.1
		self.learningRate_min=0.01
		self.iterator=0   #当前迭代次数
		self.iterator_max=2500
		self.mc=0.3    #动量因子，用于调控权值
		self.eb=0.01   #误差容限

		#以下属性通过其他函数生成

		self.nNode=4  #隐含层节点，默认为4
		self.nIn=0    #输入层节点
		self.nOut=1   #输出层节点,默认为1
		self.example=0 #样例个数
		self.errorList=[]  #误差列表
		self.dataMat=[]    #训练集
		self.classLabels=[]  #分类标签集，作为期望输出

	def	init_hiddenWB(self):     #初始化输入层与隐含层之间的权重向量
		self.hi_w=(random.rand(self.nNode,self.nIn)-0.5)*2
		self.hi_b=(random.rand(self.nNode,1)-0.5)*2  #对应于偏倚单位
		self.hi_wb=concatenate((self.hi_b,self.hi_w),axis=1)
	def init_OutputWB(self):     #初始化隐含层与输出层之间的权重向量
		self.oh_w=(random.rand(self.nOut,self.nNode)-0.5)*0.5
		self.oh_b=(random.rand(self.nOut,1)-0.5)*2   #对应于偏倚单位
		self.oh_wb=concatenate((self.oh_b,self.oh_w),axis=1)

	def loadDataMat(self,filename):
		fr=open(filename)
		for line in fr.readlines():
			lineArr=line.strip().split('\t')
			self.classLabels.append(int(lineArr[-1]))  #分类标签集，作为期望输出
			lineArr=[1]+[float(lineArr[i]) for i in range(len(lineArr)-1)]
			self.dataMat.append(lineArr)
		self.dataMat=mat(self.dataMat)
		self.classLabels=mat(self.classLabels).T
		m,n=shape(self.dataMat)  #这里的n已经包括了偏倚单位
		self.nIn=n-1
		self.example=m

	def normalize1(self):   #数据集归一化  min-max标准化（Min-Max Normalization）
		[m,n]=shape(self.dataMat)
		for i in range(1,n):
			self.dataMat[:,i]=(self.dataMat[:,i]-min(self.dataMat[:,i]))/(max(self.dataMat[:,i])-min(self.dataMat[:,i]))
	def normalize2(self):	#数据集归一化  Z-score标准化方法
		[m,n]=shape(self.dataMat)
		for i in range(1,n):
			self.dataMat[:,i]=(self.dataMat[:,i]-mean(self.dataMat[:,i]))/(std(self.dataMat[:,i])+1.0e-10)

	def drawClassScatter(self):  #绘制数据集的二维离散点
		n=self.dataMat.shape[1]
		i=0
		if n==3:
			fig=plt.figure()
			ax=fig.add_subplot(111)
			for mydata in self.dataMat:
				if self.classLabels[i]==0:
					ax.scatter(mydata[0,1],mydata[0,2],c='blue',marker='o')
				if self.classLabels[i]==1:
					ax.scatter(mydata[0,1],mydata[0,2],c='red',marker='o')
				i+=1
		else:
			print ('can not plot the dataMat')

	def logistic(self,inX):
		return 1/(1+exp(-inX))
	def gradient_logistic(self,net):
		return multiply(net,1.0-net)

	#主函数

	def forward_propagate(self):	#前向传播过程
		self.hi=self.dataMat*self.hi_wb.T  #(m*nNode)
		self.ho=self.logistic(self.hi)               #(m*nNode)
		self.ho_bias=concatenate((ones((self.example,1)),self.ho),axis=1) #(m*nNode+1)
		self.yi=self.ho_bias*self.oh_wb.T  #(m*nOut)
		self.yo=self.logistic(self.yi)     #(m*nOut)

	def cost(self,err):
		return sum(power(err,2))*0.5

	def backward_propagate(self):		#反向传播过程
		#输出层
		Delta=multiply(self.classLabels-self.yo,self.gradient_logistic(self.yo)) #(m*nOut)
		gradient_oh=Delta.T*self.ho_bias  #(nOut*nNode+1)
		#隐含层
		delta=multiply(Delta*self.oh_wb[:,1:],self.gradient_logistic(self.ho)) #(m*nNode)
		gradient_hi=delta.T*self.dataMat  #(nNode*nIn+1)
		return gradient_hi,gradient_oh

	def bpnet(self):
		self.normalize1()
		self.normalize2()
		self.init_hiddenWB()  #初始化输入层与隐含层之间的权重向量
		self.init_OutputWB()  #初始化隐含层与输出层之间的权重向量
		dhi=0.0;doh=0.0;  #t-1时刻的权重微分，初始为0
		for i in range(self.iterator_max):
				self.iterator=i+1
				#print 'iter:',i+1
				self.forward_propagate()  #前向传播过程
				err=self.classLabels-self.yo
				sse=self.cost(err)
				self.errorList.append(sse)
				if sse<=self.eb:
					break;

				gradient_hi,gradient_oh=self.backward_propagate()  #权重微分
				if i<10000:
					self.oh_wb=self.oh_wb+self.learningRate*gradient_oh   #更新权重
					self.hi_wb=self.hi_wb+self.learningRate*gradient_hi
				else:
					self.hi_wb=self.hi_wb+(1.0-self.mc)*self.learningRate*gradient_hi+self.mc*dhi   #网络调优的做法
					self.oh_wb=self.oh_wb+(1.0-self.mc)*self.learningRate*gradient_oh+self.mc*doh
					dhi=gradient_hi
					doh=gradient_oh
				#self.learningRate=self.learningRate_max-i*(self.learningRate_max-self.learningRate_min)/self.iterator_max   #变学习率
		return self.hi_wb,self.oh_wb

	def Desicion_boundary(self,step=100):
		n=self.dataMat.shape[1]
		if n==3:
			amin=min(min(self.dataMat.tolist()))
			amax=max(max(self.dataMat.tolist()))
			print(amin,amax)
			x=linspace(int(round(amin)),int(round(amax)),step)
			#print x
			#print 'x:',len(x)
			xx=mat(ones((step,step)))
			xx[:,0:step]=x
			yy=xx.T
			xi=[]
			z=ones((len(xx),len(yy)))
			for i in range(len(xx)):
				for j in range(len(xx)):
					xi=mat([1,xx[i,j],yy[i,j]])
					hi_input=self.hi_wb*xi.T
					hi_out=self.logistic(hi_input)
					hi_out_bias=concatenate((mat([1]),hi_out),axis=0)
					#print hi_out_bias.shape
					oh_input=self.oh_wb*hi_out_bias
					oh_out=self.logistic(oh_input)
					z[i,j]=oh_out

		return x,z

	def classfierLine(self,x,z):
		#print 'x,z:',x,z
		x,y=meshgrid(x,x)
		#print z.shape
		plt.contour(x,y,z,1,colors='black')

	def TrendLine(self):
		x=range(0,self.iterator)
		y=log2(self.errorList)
		print (y)
		plt.plot(x,y,color='r')
		plt.show()

a=BPnet()
a.loadDataMat(r'D:\python_learning_dataes\testSet2.txt')
print (a.dataMat.shape)   #(307,3)
print (a.classLabels.shape)	#(307,1)
#print a.dataMat
a.normalize1()
a.normalize2()
a.bpnet()
a.drawClassScatter()
x,z=a.Desicion_boundary()
a.classfierLine(x,z)
plt.show()
a.TrendLine()
plt.show()


from Modules import GenericCrawlerandExtractor
from Modules import InputMethods
from Modules import CommonFunctions
import json
import re

CONFIG_PATH = '/home/rb1307/Samagra Patrika/News_Feed_automation_system/Modules/NewsPaper_configs'
CONFIG_FILE = 'configs_TOI.json'

class TOI(GenericCrawlerandExtractor.GCA):
    def __init__(self, **kwargs):
        self.source_configs = {}
        self.source_configs.update(kwargs)
        config_data = InputMethods.input_json(path=CONFIG_PATH, file_name=CONFIG_FILE)
        self.source_configs['extractor_configs'] = config_data
        super().__init__(**self.source_configs)
        self.xml_tree = super().convertresponsetoxmltree()

    def getarticleidfromurl(self):
        article_id = self.source_configs.get("url").split("/articleshow/")[-1].split(".")[0]
        return article_id

    def getjsonobject(self):
        article_response = super().return_reponse()
        json_string = re.search("window.App=(.*?)</script><script>", article_response).group(1)
        json_obj = json.loads(json_string)

        return json_obj

    def extractarticlebody_json(self):
        article_id = self.getarticleidfromurl()
        json_dict = self.getjsonobject()
        story_list = json_dict.get("state", {}).get("articleshow", {}).get("data", {}).get(str(article_id), {})\
            .get("story", [])
        story =[]
        for items in story_list:
            if items.get("tn") in ['text', 'keywoard']:
                story.append(items.get("value"))
        article_body = CommonFunctions.clean_article_body(body_list=story)

        return article_body

    def extractkeywords_json(self):
        article_id = self.getarticleidfromurl()
        json_dict = self.getjsonobject()
        keywords = json_dict.get("state", {}).get("articleshow", {}).get("data", {}).get(str(article_id), {})\
            .get("kws", '')

        return keywords

    def extractimagelink_json(self):
        base_url ='https://static.toiimg.com/thumb/msid-'
        image_url =base_url +str(self.getarticleidfromurl()) + ',imgsize-162203/photo.jpg'
        return image_url

def getsourceresponse(**kwargs):
    obj = TOI(**kwargs)
    resp={'article_id': obj.getarticleidfromurl(), 'article_body': obj.extractarticlebody_xml(),
          'provided_keywords': obj.extractkeywords_json(), 'image': obj.extractimagelink_json(),
          'source_id': kwargs.get("source_id")}
    return resp


while True:
    length = list(map(int, input().split()))
    if length.count(0) == 3:
        break
    else:
        length.sort()
        x = length[0]
        y = length[1]
        z = length[2]
        if x ** 2 + y ** 2 == z ** 2:
            print("right")
        else:
            print("wrong")

백준 4153 직각 삼각형.py


# -*- coding:utf-8 -*-
from imp import reload
from Tkinter import *
import time
import os
def a2():#后退小车左移动
    c1=Button(root,image=im3)
    c1.update()
    for a in range(900,0,-1):
        c1.place(x=a,y=600)
        c1.update()
        time.sleep(0.0001)
    root.destroy()
def a20():
    a2()
    os.system("menu.py")
def a1(m,x1,y1):#小车右移动
    c=Button(root,image=im2)
    c.update()
    for a in range(x1,y1):
        c.place(x=a,y=100*m)
        c.update()
        time.sleep(0.0001)
    canvas.delete(xt,d[0],d[1],d[2],d[3],d[4])
    c2.config(command=a20)
def dwsy1():
    a1(1,50,1000)
    root.destroy()
    os.system("dwsy10.py")
def dwsy2():
    a1(2,50,1000)
    root.destroy()
    os.system("dwsy20.py")
def dwsy3():
    a1(3,50,1000)
    root.destroy()
    os.system("dwsy30.py")
def dwsy4():
    a1(4,50,1000)
    root.destroy()
    os.system("dwsy40.py")
def dwsy5():
    a1(5,50,1000)
    root.destroy()
    os.system("dwsy5.py")
def math1():
    a1(1,50,1000)
    root.destroy()
    os.system("math1.py")
def math2():
    a1(2,50,1000)
    root.destroy()
    os.system("math2.py")
def math3():
    a1(3,50,1000)
    root.destroy()
    os.system("math3.py")
def math4():
    a1(4,50,1000)
    root.destroy()
    os.system("math4.py")
def math5():
    a1(5,50,1000)
    root.destroy()
    os.system("math5.py")
def tl1():
    a1(1,50,1000)
    root.destroy()
    os.system("hungary.py")
def tl2():
    a1(2,50,1000)
    root.destroy()
    os.system("kruscal.py")
def tl3():
    a1(3,50,1000)
    root.destroy()
    os.system("tarjan.py")
def tl4():
    a1(4,50,1000)
    root.destroy()
    os.system("zdlj.py")
def tl5():
    pass

def data1():
    a1(1,50,1000)
    root.destroy()
    os.system("fitting.py")
def data2():
    a1(2,50,1000)
    root.destroy()
    os.system("pca.py")
def data3():
    a1(3,50,1000)
    root.destroy()
    os.system("kmeans.py")
def data4():
    pass
def data5():
    pass

def b1():  #进入科学计算器
    a1(1,50,1000)
    root.destroy()
    os.system("kxjsq.py")
def b2():#进入高数&现代
    a1(2,50,1000)
    d2=canvas.create_text(500,50,text='基于Python的专业辅助计算系统-->高等数学&线性代数',fill='white',font=('', 20,'bold'))
    a=['绘图(直角坐标)','绘图（对数坐标&极坐标）','微积分计算','线性代数','函数查询']
    for i in range(5):
        d[i]=canvas.create_text(500,150+100*i,text=a[i],fill='yellow',font=('', 20,'bold'))
    for i in range(5):
        b[i].config(command=math[i])

def b3():#进入大物实验
    a1(3,50,1000)
    d2=canvas.create_text(500,50,text='基于Python的专业辅助计算系统-->大物实验',fill='white',font=('', 20,'bold'))
    a=['杨氏模量拉伸法','元电荷测定-密立根油滴','光栅衍射','动态杨氏','实验查询']
    for i in range(5):
        d[i]=canvas.create_text(500,150+100*i,text=a[i],fill='yellow',font=('', 20,'bold'))
    for i in range(5):
        b[i].config(command=dwsy[i])
def b4():#进入数据处理
    a1(4,50,1000)
    data=[data1,data2,data3,data4,data5]
    d2=canvas.create_text(500,50,text='基于Python的专业辅助计算系统-->大数据处理',fill='white',font=('', 20,'bold'))
    a=['最小二乘拟合','数据降维','k均值聚类','...','...']
    for i in range(5):
        d[i]=canvas.create_text(500,150+100*i,text=a[i],fill='yellow',font=('', 20,'bold'))
    for i in range(5):
        b[i].config(command=data[i])

def b5():#进入图论
    a1(5,50,1000)
    tl=[tl1,tl2,tl3,tl4,tl5]
    d2=canvas.create_text(500,50,text='基于Python的专业辅助计算系统-->图论',fill='white',font=('', 20,'bold'))
    a=['二分图最大匹配','最小生成树','强连通图判断','最短路径','...']
    for i in range(5):
        d[i]=canvas.create_text(500,150+100*i,text=a[i],fill='yellow',font=('', 20,'bold'))
    for i in range(5):
        b[i].config(command=tl[i])

root = Tk()
canvas = Canvas(root,width = 1000, height = 666)
im2=PhotoImage(file='0053.gif')

im=PhotoImage(file='bg.gif')
im3=PhotoImage(file='3.gif')
canvas.create_image(500,333,image = im)
xt=canvas.create_text(500,50,text='基于Python的专业辅助计算系统',fill='white',font=('', 30,'bold'))
canvas.create_line(300,100,300,600,fill='white',width=10,dash=2)
canvas.create_line(780,100,780,600,fill='white',width=10,dash=2)
a=['科学计算器','高等数学&线性代数','大物实验','数据分析','图论']
b=[1,2,3,4,5]
d=[1,2,3,4,5]
c=[b1,b2,b3,b4,b5]

dwsy=[dwsy1,dwsy2,dwsy3,dwsy4,dwsy5]
math=[math1,math2,math3,math4,math5]
for i in range(6):
    canvas.create_line(200,100*i+100,800,100*i+100,fill='white',width=10)
    if i==5:break
    canvas.create_text(250,150+100*i,text=b[i],fill='white',width=10,font=('', 80))
    d[i]=canvas.create_text(500,150+100*i,text=a[i],fill='yellow',font=('', 25,'bold'))
    b[i]=Button(root,image=im2,command=c[i])
    b[i].place(x=50,y=100*i+100)
c2=Button(root,image=im3,command=a2)
c2.place(x=900,y=600)
canvas.pack()
root.mainloop()


import jax
import jax.numpy as jnp
from jax import grad, jit, vmap
from functools import partial
from jax import random
import os
import mlflow

# Switch off the cache
os.environ['XLA_PYTHON_CLIENT_PREALLOCATE'] = 'false'
os.environ['XLA_PYTHON_CLIENT_ALLOCATOR'] = 'platform'

class Logistic_Regression():
    """
    Basic Model + Quasi Newton Methods
    """
    def __init__(self, regularization='l2', method_opt='classic_model'):
        self.regularization = regularization
        self.method_opt = method_opt
        self.error_gradient = 0.001
        self.key = random.PRNGKey(0)
        self.cpus = jax.devices("cpu")
        # You need to add some variables
        self.W = None

    @staticmethod
    @jit
    def logistic_exp(W:jnp, X:jnp)->jnp:
        """
        Generate all the w^T@x values
        args:
            W is a k-1 x d + 1
            X is a d x N
        """
        return jnp.exp(W@X)

    @staticmethod
    @jit
    def logistic_sum(exTerms: jnp)->jnp:
        """
        Generate all the w^T@x values
        args:
            W is a k-1 x d
            X is a d x N
        """
        temp = jnp.sum(exTerms, axis=0)
        n = temp.shape[0]
        return jnp.reshape(1.0+temp, newshape=(1, n))

    @staticmethod
    @jit
    def logit_matrix(Terms: jnp, sum_terms: jnp)->jnp:
        """
        Generate matrix
        """
        divisor = 1/sum_terms
        n, _ = Terms.shape
        replicate = jnp.repeat(divisor, repeats=n, axis=0 )
        logits = Terms*replicate
        return jnp.vstack([logits, divisor])

    @partial(jit, static_argnums=(0,))
    def model(self, W:jnp, X:jnp, Y_hot:jnp,lamda=0)->jnp:
        """
        Logistic Model, and regularized model with lamda !=0
        """
        W = jnp.reshape(W, self.sh)
        terms = self.logistic_exp(W, X)
        sum_terms = self.logistic_sum(terms)
        matrix = self.logit_matrix(terms, sum_terms)
        #print("este es el logic matrix", matrix.shape)
        return jnp.sum(jnp.sum(jnp.log(matrix)*Y_hot, axis=0), axis=0) + lamda*jnp.trace(jnp.transpose(W)@(W))#devuelve el error total de la suma de las probabilidades y*log(x|w)

    @staticmethod
    def one_hot(Y: jnp):
        """
        One_hot matrix
        """
        numclasses = len(jnp.unique(Y))
        return jnp.transpose(jax.nn.one_hot(Y, num_classes=numclasses))

    def generate_w(self, k_classes:int, dim:int)->jnp:
        """
        Use the random generator at Jax to generate a random generator to instanciate
        the augmented values
        """
        key = random.PRNGKey(0)
        keys = random.split(key, 1)
        return jnp.array(random.normal(keys[0], (k_classes, dim)))

    @staticmethod
    def augment_x(X: jnp)->jnp:
        """
        Augmenting samples of a dim x N matrix
        """
        N = X.shape[1]
        return jnp.vstack([X, jnp.ones((1, N))])

    def fit(self, X: jnp, Y:jnp,lr,tol,lamda,n_max_steps)->None:
        """
        The fit process
        """
        nclasses = len(jnp.unique(Y))
        X = self.augment_x(X)
        dim = X.shape[0]
        W = self.generate_w(nclasses-1, dim)
        Y_hot = self.one_hot(Y)
        #print(Y_hot)
        self.W = getattr(self, self.method_opt, lambda W, X, Y_hot, lr,tol,lamda, n_max_steps: self.error() )(W, X, Y_hot,lr,tol,lamda, n_max_steps)
        return self.W

    @staticmethod
    def error()->None:
        """
        Only Print Error
        """
        raise Exception("Opt Method does not exist")

    def classic_model(self, W:jnp, X:jnp, Y_hot:jnp, lr:float=1e-9,  tol:float=1e-3, lamda=0, n_max_steps=200)->jnp:
        """
        The naive version of the logistic regression
        """
        n, m = W.shape
        self.sh = (n, m)
        Grad = jax.grad(self.model, argnums=0)(jnp.ravel(W), X, Y_hot,lamda)

        loss = self.model(jnp.ravel(W), X, Y_hot,lamda)
        cnt = 0
        while True:
            Hessian = jax.hessian(self.model, argnums=0)(jnp.ravel(W), X, Y_hot,lamda)
            W = W - lr*jnp.reshape((jnp.linalg.inv(Hessian)@Grad), self.sh)
            Grad =  jax.grad(self.model, argnums=0)(jnp.ravel(W), X, Y_hot,lamda)
            old_loss = loss
            loss = self.model(jnp.ravel(W), X, Y_hot,lamda)
            if cnt%200 == 0:
                print('step:',cnt,'loss:',f'{self.model(jnp.ravel(W), X, Y_hot,lamda)}')
            #if  jnp.abs(old_loss - loss) < tol:
                #break
            cnt +=1
            if cnt > n_max_steps:
                break
        return W

    def estimate(self, X:jnp)->jnp:
        """
        Estimation
        """
        X = self.augment_x(X)
        terms = self.logistic_exp(self.W, X)
        sum_terms = self.logistic_sum(terms)
        matrix = self.logit_matrix(terms, sum_terms)
        return jnp.argmax(matrix, axis=0)

    def precision(self, y, y_hat):
        """
        Precision
        args:
            y: Real Labels
            y_hat: estimated labels
        return TP/(TP+FP)
        """
        TP = sum(y_hat == y)
        FP = sum(y_hat != y)
        return (TP/(TP+FP)).tolist()

    def precision_jax(self, y, y_hat):
        """
        precision
        args:
            y: Real Labels
            y_hat: estimated labels
        return TP/(TP+FP)
        """
        TP = jnp.sum((y > 0) & (y_hat > 0))
        FP = jnp.sum((y <= 0) & (y_hat > 0))

        #evitar division por cero
        precision_cpu = jax.lax.cond(
            TP + FP == 0,
            lambda _: 0.0,
            lambda _: TP / (TP + FP),
            operand=None,
        )

        return float(precision_cpu)

    def recall_jax(self,y, y_hat):
        """
            recall
            args:
                y: Real Labels
                y_hat: estimated labels
            return TP/(TP+FN)
        """
        TP = jnp.sum((y > 0) & (y_hat > 0))
        FN = jnp.sum((y > 0) & (y_hat <= 0))

        #evitar division por cero
        recall_cpu = jax.lax.cond(
            TP + FN == 0,
            lambda _: 0.0,
            lambda _: TP / (TP + FN),
            operand=None,
        )

        return float(recall_cpu)

    def accuracy_jax(self,y, y_hat):
        """
            accuracy
            args:
                y: Real Labels
                y_hat: estimated labels
            return  TP +TN/ TP +FP +FN+TN
        """
        TP = jnp.sum((y > 0) & (y_hat > 0))
        FP = jnp.sum((y <= 0) & (y_hat > 0))
        FN = jnp.sum((y > 0) & (y_hat <= 0))
        TN = jnp.sum((y <= 0) & (y_hat <= 0))

        #evitar division por cero
        if (TP+FP+TN+FN)==0:
            return 0
        else:
            accuracy_cpu = jit(lambda x: x, device=self.cpus[0])((TP+TN)/(TP+FP+TN+FN))
            return float(accuracy_cpu)

    def normalize_columns(self,arr):
        """
        Normalizes an array of shape (n, m) by column using the min-max scaling method.
        """
        mins = jnp.min(arr, axis=0)
        maxs = jnp.max(arr, axis=0)
        return (arr - mins) / (maxs - mins)

def LogisticRegression(X, Y, X_val,Y_val,lr,tol,lamda,n_max_steps)->jnp:
    """
    Logistic Regression
    args:
        X: dataset de dimension (samples, features)
        Y: labels (entre 0 y 1) de dimension (samples,)
    return:
        Y_hat: estimated labels de dimension (samples,)
        precision: precision of the model
    """
    #----------------------------mlflow--------------------------------
    experiment_name = "LogisticRegression"
    # Verificar si el experimento ya existe
    experiment = mlflow.get_experiment_by_name(experiment_name)

    if experiment is None:
        # Si no existe, crear el experimento
        experiment_id = mlflow.create_experiment(experiment_name)
    else:
        # Si ya existe, obtener el experimento
        experiment_id = experiment.experiment_id

    with mlflow.start_run(experiment_id=experiment_id,run_name="LogisticRegression") as run:
        numero_features=X.shape[1]
        #log params
        mlflow.log_param("lr", lr)
        mlflow.log_param("tol", tol)
        mlflow.log_param("lamda", lamda)
        mlflow.log_param("n_max_steps", n_max_steps)
        mlflow.log_param("NumberOfFeatures", numero_features)
    #------------------------------------------------------------------
        #garantizamos que sean jax arrays
        X = jnp.array(X)
        Y = jnp.array(Y)
        model = Logistic_Regression()
        X= model.normalize_columns(X)
        #trasnponemos X ya que siguientes funciones asumen que es de dimension (features, samples)
        X = jnp.transpose(X)
        w_logistic=model.fit(X, Y, lr,tol,lamda,n_max_steps)

        Y_hat = model.estimate(X)
        precision=model.precision_jax(Y, Y_hat)
        recall=model.recall_jax(Y, Y_hat)
        accuracy=model.accuracy_jax(Y, Y_hat)

        print('----------------------Metricas con datos de entrenamiento----------------------')
        print(f'precision: {precision}')
        print(f'recall: {recall}')
        print(f'accuracy: {accuracy}')

        #log metrics
        mlflow.log_metric("precision", precision)
        mlflow.log_metric("recall", recall)
        mlflow.log_metric("accuracy", accuracy)

        #-----------------------------validacion--------------------------------

        Y_hat_val, precision_val, recall_val, accuracy_val=prediction_trained_logistic(X_val,w_logistic, Y_val)

        print('----------------------Metricas con datos de validacion----------------------')
        print(f'precision: {precision_val}')
        print(f'recall: {recall_val}')
        print(f'accuracy: {accuracy_val}')

        #log metrics
        mlflow.log_metric("precision_validation", precision_val)
        mlflow.log_metric("recall_validation", recall_val)
        mlflow.log_metric("accuracy_validation", accuracy_val)

        return w_logistic,Y_hat, precision, recall, accuracy

def prediction_trained_logistic(X,w_logistic, Y=None):
    """
    Prediction with trained logistic regression
    args:
        X_val: dataset de dimension (samples, features)
        w_logistic: trained weights
    return:
        Y_hat: estimated labels de dimension (samples,)
        precision: precision of the model
    """
    #garantizamos que sean jax arrays
    X = jnp.array(X)
    Y = jnp.array(Y)
    model_prediction = Logistic_Regression()
    X= model_prediction.normalize_columns(X)
    #trasnponemos X ya que siguientes funciones asumen que es de dimension (features, samples)
    X = jnp.transpose(X)
    model_prediction.W = w_logistic
    Y_hat = model_prediction.estimate(X)

    if Y is not None:
        precision=model_prediction.precision_jax(Y, Y_hat)
        recall=model_prediction.recall_jax(Y, Y_hat)
        accuracy=model_prediction.accuracy_jax(Y, Y_hat)
        return Y_hat, precision, recall, accuracy

    else:
        return Y_hat

if __name__ == "__main__":
    w_logistic,Y_hat, precision, recall, accuracy = LogisticRegression(X, Y,X_val,y_val, lr,tol,lamda,n_max_steps)
    prediction_trained_logistic(X,w_logistic)


# -*- coding: utf-8 -*-
"""Higher-order Structure based Anomaly Detection on Attributed
    Networks (GUIDE)"""
# Author: Kay Liu <zliu234@uic.edu>
# License: BSD 2 clause

import os
import warnings

import torch
import torch.nn.functional as F

from . import DeepDetector
from ..nn import GUIDEBase

class GUIDE(DeepDetector):
    """
    Higher-order Structure based Anomaly Detection on Attributed
    Networks

    GUIDE is an anomaly detector consisting of an attribute graph
    convolutional autoencoder, and a structure graph attentive
    autoencoder (not the same as the graph attention networks). Instead
    of the adjacency matrix, node motif degree is used as input of
    structure autoencoder. The reconstruction mean square error of the
    autoencoders are defined as structure anomaly score and attribute
    anomaly score, respectively.

    Note: The calculation of node motif degree in preprocessing has
    high time complexity. It may take longer than you expect.

    See :cite:`yuan2021higher` for details.

    Parameters
    ----------
    hid_a : int, optional
        Hidden dimension for attribute. Default: ``64``.
    hid_s : int, optional
        Hidden dimension for structure. Default: ``4``.
    num_layers : int, optional
        Total number of layers in model. Default: ``4``.
    dropout : float, optional
        Dropout rate. Default: ``0.``.
    weight_decay : float, optional
        Weight decay (L2 penalty). Default: ``0.``.
    act : callable activation function or None, optional
        Activation function if not None.
        Default: ``torch.nn.functional.relu``.
    backbone : torch.nn.Module
        The backbone of GUIDE is fixed. Changing of this
        parameter will not affect the model. Default: ``None``.
    alpha : float, optional
        Weight between reconstruction of node feature and structure.
        Default: ``0.5``.
    contamination : float, optional
        The amount of contamination of the dataset in (0., 0.5], i.e.,
        the proportion of outliers in the dataset. Used when fitting to
        define the threshold on the decision function. Default: ``0.1``.
    lr : float, optional
        Learning rate. Default: ``0.004``.
    epoch : int, optional
        Maximum number of training epoch. Default: ``100``.
    gpu : int
        GPU Index, -1 for using CPU. Default: ``-1``.
    batch_size : int, optional
        Minibatch size, 0 for full batch training. Default: ``0``.
    num_neigh : int, optional
        Number of neighbors in sampling, -1 for all neighbors.
        Default: ``-1``.
    graphlet_size : int, optional
        The maximum size of graphlet. Default: ``4``.
    selected_motif : bool, optional
        Whether to use selected motif in the paper. Default: ``True``.
    cache_dir : str, optional
        The directory for the node motif degree caching. If ``None``,
        ~/.pygod will be used. Default: ``None``.
    verbose : int, optional
        Verbosity mode. Range in [0, 3]. Larger value for printing out
        more log information. Default: ``0``.
    save_emb : bool, optional
        Whether to save the embedding. Default: ``False``.
    compile_model : bool, optional
        Whether to compile the model with ``torch_geometric.compile``.
        Default: ``False``.
    **kwargs
        Other parameters for the backbone.

    Attributes
    ----------
    decision_score_ : torch.Tensor
        The outlier scores of the training data. Outliers tend to have
        higher scores. This value is available once the detector is
        fitted.
    threshold_ : float
        The threshold is based on ``contamination``. It is the
        :math:`N`*``contamination`` most abnormal samples in
        ``decision_score_``. The threshold is calculated for generating
        binary outlier labels.
    label_ : torch.Tensor
        The binary labels of the training data. 0 stands for inliers
        and 1 for outliers. It is generated by applying
        ``threshold_`` on ``decision_score_``.
    emb : torch.Tensor or tuple of torch.Tensor or None
        The learned node hidden embeddings of shape
        :math:`N \\times` ``hid_dim``. Only available when ``save_emb``
        is ``True``. When the detector has not been fitted, ``emb`` is
        ``None``. When the detector has multiple embeddings,
        ``emb`` is a tuple of torch.Tensor.
    """

    def __init__(self,
                 hid_a=64,
                 hid_s=4,
                 num_layers=4,
                 dropout=0.,
                 weight_decay=0.,
                 act=F.relu,
                 backbone=None,
                 alpha=0.5,
                 contamination=0.1,
                 lr=0.004,
                 epoch=100,
                 gpu=-1,
                 batch_size=0,
                 num_neigh=-1,
                 graphlet_size=4,
                 selected_motif=True,
                 cache_dir=None,
                 verbose=0,
                 save_emb=False,
                 compile_model=False,
                 **kwargs):

        if backbone is not None:
            warnings.warn("Backbone is not used in GUIDE")

        super(GUIDE, self).__init__(hid_dim=(hid_a, hid_s),
                                    num_layers=num_layers,
                                    dropout=dropout,
                                    weight_decay=weight_decay,
                                    act=act,
                                    backbone=backbone,
                                    contamination=contamination,
                                    lr=lr,
                                    epoch=epoch,
                                    gpu=gpu,
                                    batch_size=batch_size,
                                    num_neigh=num_neigh,
                                    verbose=verbose,
                                    save_emb=save_emb,
                                    compile_model=compile_model,
                                    **kwargs)

        self.dim_s = None
        self.alpha = alpha
        self.graphlet_size = graphlet_size
        if selected_motif:
            assert self.graphlet_size == 4, \
                "Graphlet size is fixed when using selected motif"
        self.selected_motif = selected_motif
        self.verbose = verbose
        self.cache_dir = cache_dir

    def process_graph(self, data):

        data.s = GUIDEBase.calc_gdd(data,
                                    self.cache_dir,
                                    graphlet_size=self.graphlet_size,
                                    selected_motif=self.selected_motif)
        self.dim_s = data.s.shape[1]

    def init_model(self, **kwargs):
        if self.save_emb:
            self.emb = (torch.zeros(self.num_nodes, self.hid_dim[0]),
                        torch.zeros(self.num_nodes, self.hid_dim[1]))

        return GUIDEBase(dim_a=self.in_dim,
                         dim_s=self.dim_s,
                         hid_a=self.hid_dim[0],
                         hid_s=self.hid_dim[1],
                         num_layers=self.num_layers,
                         dropout=self.dropout,
                         act=self.act,
                         **kwargs).to(self.device)

    def forward_model(self, data):

        batch_size = data.batch_size

        x = data.x.to(self.device)
        s = data.s.to(self.device)
        edge_index = data.edge_index.to(self.device)

        x_, s_ = self.model(x, s, edge_index)

        score = self.model.loss_func(x[:batch_size],
                                     x_[:batch_size],
                                     s[:batch_size],
                                     s_[:batch_size],
                                     self.alpha)

        loss = torch.mean(score)

        return loss, score.detach().cpu()


from __future__ import absolute_import, unicode_literals

from datetime import date
from decimal import Decimal
from typing import List

from celery import task
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from tracker.models import Expense

from price_scraper.models import Price, Product

WEBDRIVER_PATH = "/home/dawid/financestracker/chromedriver"
NOT_FOUND_MESSAGE = "Nie znaleziono produktów spełniających kryteria wyszukiwania."
STOKROTKA_PATH = "https://sklep.stokrotka.pl/szukaj/?search=product&string="
STOKROTKA_ITEM_XPATH = "/html/body/div[3]/div/div[2]/div[2]/div[1]"

@task()
def get_prices():
    # Scrapes web to find prices of today added expense
    items_name = Expense.objects.filter(date__date=date.today()).values_list(
        "title", flat=True
    )
    for item in items_name:
        response = fetch_data(item)
        # Clear data
        if NOT_FOUND_MESSAGE in response:
            continue
        else:
            add_or_update_product(clear_data(response))

def fetch_data(item_name, path=STOKROTKA_PATH, xpath=STOKROTKA_ITEM_XPATH):
    # Configure
    options = Options()
    options.headless = True
    options.add_argument("--window-size=1920,1200")

    # Fetch data
    driver = webdriver.Chrome(options=options, executable_path=WEBDRIVER_PATH)
    driver.get(f"{path}{item_name}")
    response = driver.find_elements_by_xpath(xpath)[0].text
    driver.close()
    return response

def clear_data(response):
    response = (
        response.replace("\n▾", "")
        .replace("\n▴", "")
        .replace(",", ".")
        .replace("zł", "")
        .split("\n")
    )
    response_iterator = iter(response)
    return list(zip(response_iterator, response_iterator))

def add_or_update_product(items: List):
    for item in items:
        # If there are 2 prices (old, new) grab only current
        value = item[1].split(" ")[0]
        value = Decimal(value)
        product = Product.objects.filter(title=item[0])
        product = Price.objects.filter(product__title=item[0], value=value)
        if not product:
            product = Product.objects.create(title=item[0], category="spozywcze")
            product.save()
            price = Price.objects.create(
                shop_name="Stokrotka", value=value, product=product
            )
            price.save()
            print(f"Save product {product} with {price}")
        else:
            print("This item already exist")
            continue


from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

tokenizer = AutoTokenizer.from_pretrained("voidful/bart-distractor-generation-both")
model = AutoModelForSeq2SeqLM.from_pretrained("voidful/bart-distractor-generation-both")
maxLength = 1024

def getDistractors(context, question, answer, nDistractors):
    QAinput = ' </s> ' + question + ' </s> ' + answer
    length = maxLength - len(QAinput)
    input = context[:length] + QAinput
    output = tokenizer.batch_decode(model.generate(tokenizer.encode(input,return_tensors='pt'),num_return_sequences=nDistractors,num_beams=nDistractors))

    distractors = []
    for item in output:
        distractor = item.replace("</s>", "").replace("<pad>", "")
        distractors.append(distractor)

    return distractors


from django.urls import path

from .views import RegistrationAPIView, LoginAPIView, RefreshAPIView
from rest_framework_swagger.views import get_swagger_view
from django.conf.urls import url

schema_view = get_swagger_view(title='Pastebin API')

app_name = 'authentication'
urlpatterns = [
    path('users/' ,RegistrationAPIView.as_view({
        'post': 'registration',
    })),
    path('users/login/', LoginAPIView.as_view()),
    path('users/refresh/', RefreshAPIView.as_view()),
    path('users/<uuid:uuid>', RegistrationAPIView.as_view({
        'get': 'verify',
    })),
    url(r'^$', schema_view)
]