import time
from ratelimit.mixins import RatelimitMixin
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.db.models import Count
from django.http import HttpResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import (CreateView, DeleteView, DetailView, FormView,
                                  ListView, TemplateView, UpdateView, View)

from apps.challenges.forms import (AttachmentAddForm, AttachmentDeleteForm,
                                   FlagAddForm, FlagDeleteForm, HintAddForm,
                                   HintDeleteForm, NewChallengeForm,
                                   SubmitFlagForm)
from apps.challenges.models import (Attachment, BadSubmission, Category,
                                    Challenge, FirstBlood, Flag, Solves,
                                    Hint)
from apps.scoreboard.utils import get_key

class UserIsAdminMixin(UserPassesTestMixin):
    def test_func(self):
        return self.request.user.is_staff

class CtfNotEnded(UserPassesTestMixin):
    def test_func(self):
        if get_key('start_time') is None or get_key('end_time') is None:
            return True
        elif int(get_key('start_time')) < int(time.time()) < int(get_key('end_time')):
            return True
        else:
            return False

class ChallengesListView(LoginRequiredMixin, View):

    def get(self, request, *args, **kwargs):
        context = {}
        solves = Solves.objects.prefetch_related(
            'challenge').prefetch_related('account')

        context['challenges'] = Challenge.objects.prefetch_related(
            'category').prefetch_related('solves').all()
        context['categories'] = Category.objects.prefetch_related('challenge_set').all()
        context['solved_by_user'] = solves.prefetch_related('challenge').values_list(
            'challenge', flat=True).filter(account=self.request.user.pk)
        context['solves'] = solves.values("challenge__name").annotate(
            c=Count('challenge')).order_by('-c')
        context['first_bloods'] = FirstBlood.objects.prefetch_related(
            'account').prefetch_related('challenge')
        return render(self.request, 'templates/challenge/list_challenges.html', context=context)

class SubmitFlagView(RatelimitMixin, CtfNotEnded, LoginRequiredMixin, FormView):
    ratelimit_key = 'user'
    ratelimit_rate = '10/m'
    ratelimit_method = 'POST'
    ratelimit_block = True
    form_class = SubmitFlagForm

    def get_context_data(self, **kwargs):
        context = super(SubmitFlagView, self).get_context_data(**kwargs)
        context['challenge'] = Challenge.objects.get(pk=self.kwargs['pk'])
        context['solvers'] = Solves.objects.filter(
            challenge=context['challenge'])
        context['solved_by_user'] = Solves.objects.filter(
            account=self.request.user.pk).values_list('challenge', flat=True)
        return context

    def get_template_names(self):
        return list(['templates/challenge/challenge.html'])

    def form_valid(self, form):
        challenge_id = form.cleaned_data['challenge_id']
        flag = form.cleaned_data['flag']
        challenge = Challenge.objects.get(pk=challenge_id)

        if Solves.objects.filter(challenge=challenge, account=self.request.user).count() == 0:
            if flag in challenge.flag_set.all().values_list('text', flat=True):
                if Solves.objects.filter(challenge=challenge).count() == 0:
                    FirstBlood.objects.create(
                        challenge=challenge,
                        account=self.request.user,
                    )

                Solves.objects.create(
                    challenge=challenge,
                    account=self.request.user,
                )

                return render(self.request, 'templates/challenge/flag_success.html', {'challenge': challenge})
            else:
                new_bad_submission = BadSubmission.objects.create(
                    challenge=challenge,
                    account=self.request.user,
                    flag=flag
                )
                return render(self.request, 'templates/challenge/challenge.html', {'challenge': challenge, 'solvers': Solves.objects.filter(challenge=challenge), 'error': 'Wrong flag!'})
        else:
            return render(self.request, 'templates/challenge/challenge.html', {'challenge': challenge, 'solvers': Solves.objects.filter(challenge=challenge), 'error': 'Already solved!'})

class CreateChallengeView(SuccessMessageMixin, LoginRequiredMixin, UserIsAdminMixin, FormView):
    form_class = NewChallengeForm
    template_name = 'templates/challenge/new_challenge.html'
    success_url = reverse_lazy('administration:challenges')
    success_message = "Challenge %(name)s was created successfully"

    def get_context_data(self, **kwargs):
        context = super(CreateChallengeView, self).get_context_data(**kwargs)
        context['categories'] = Category.objects.all()
        return context

    def form_valid(self, form):
        category = form.cleaned_data['category']

        new_challenge = Challenge(
            category=category,
            name=form.cleaned_data['name'],
            description=form.cleaned_data['description'],
            points=form.cleaned_data['points'],
            visible=True
        )

        new_challenge.save()
        new_flag = Flag(
            challenge=new_challenge,
            text=form.cleaned_data['flag']
        )

        if self.request.FILES:
            files = self.request.FILES.getlist('attachments')
            if files:
                for f in files:
                    Attachment.objects.create(
                        challenge=new_challenge,
                        data=f
                    )

        new_flag.save()
        return super(CreateChallengeView, self).form_valid(form)

class UpdateChallengeView(UserIsAdminMixin, UpdateView):
    model = Challenge
    fields = '__all__'
    template_name = 'templates/challenge/update_challenge.html'
    success_url = reverse_lazy('administration:challenges')

class DeleteChallengeView(UserIsAdminMixin, DeleteView):
    model = Challenge
    template_name = 'templates/challenge/delete_challenge.html'
    success_url = reverse_lazy('administration:challenges')

class ToggleChallengeVisibility(UserIsAdminMixin, View):

    def post(self, request, *args, **kwargs):
        challenge_id = request.POST.get('challenge_id')
        if challenge_id is None:
            return HttpResponse(status=400)
        else:
            challenge = Challenge.objects.get(pk=challenge_id)
            if challenge.visible:
                challenge.visible = False
            else:
                challenge.visible = True
            challenge.save()
            return HttpResponse(status=204)

class AddCategoryView(UserIsAdminMixin, CreateView):
    model = Category
    fields = '__all__'
    template_name = 'templates/category/add_category.html'
    success_url = reverse_lazy('administration:challenges')

class UpdateCategoryView(UserIsAdminMixin, UpdateView):
    model = Category
    fields = '__all__'
    template_name = 'templates/category/update_category.html'
    success_url = reverse_lazy('administration:challenges')

class DeleteCategoryView(UserIsAdminMixin, DeleteView):
    model = Category
    template_name = 'templates/category/delete_category.html'
    success_url = reverse_lazy('administration:challenges')

class FlagsView(UserIsAdminMixin, DetailView):
    model = Challenge
    template_name = 'templates/challenge/flags.html'

class FlagAddView(UserIsAdminMixin, View):
    form_class = FlagAddForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(data=request.POST)
        if form.is_valid():
            challenge_id = form.cleaned_data['challenge_id']
            flag = form.cleaned_data['flag']
            challenge = Challenge.objects.get(pk=challenge_id)

            Flag.objects.create(
                challenge=challenge,
                text=flag
            )

            return HttpResponse(status=204)
        else:
            return HttpResponse(status=400)

class FlagDeleteView(UserIsAdminMixin, View):
    form_class = FlagDeleteForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            flag = form.cleaned_data['flag']
            flag = Flag.objects.get(
                pk=flag
            )
            flag.delete()

            return HttpResponse(status=204)
        else:
            return HttpResponse(status=400)

class HintsView(UserIsAdminMixin, DetailView):
    model = Challenge
    template_name = 'templates/challenge/hints.html'

class HintAddView(UserIsAdminMixin, View):
    form_class = HintAddForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            challenge_id = form.cleaned_data['challenge_id']
            hint = form.cleaned_data['hint']
            challenge = Challenge.objects.get(pk=challenge_id)

            Hint.objects.create(
                challenge=challenge,
                text=hint
            )

            return HttpResponse(status=204)
        else:
            return HttpResponse(status=400)

class HintDeleteView(UserIsAdminMixin, View):
    form_class = HintDeleteForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            hint = form.cleaned_data['hint']
            hint = Hint.objects.get(
                pk=hint
            )
            hint.delete()

            return HttpResponse(status=204)
        else:
            return HttpResponse(status=400)

class AttachmentsView(UserIsAdminMixin, DetailView):
    model = Challenge
    template_name = 'templates/challenge/attachments.html'

class AttachmentAddView(UserIsAdminMixin, View):
    form_class = AttachmentAddForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(data=request.POST, files=request.FILES)
        if form.is_valid():
            challenge_id = form.cleaned_data['challenge_id']
            attachment = form.cleaned_data['data']
            challenge = Challenge.objects.get(pk=challenge_id)

            Attachment.objects.create(
                challenge=challenge,
                data=attachment
            )

            return HttpResponse(status=204)
        else:
            return HttpResponse(status=400)

class AttachmentDeleteView(UserIsAdminMixin, View):
    form_class = AttachmentDeleteForm

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            attachment = form.cleaned_data['attachment']
            attachment = Attachment.objects.get(
                pk=attachment
            )
            attachment.delete()

            return HttpResponse(status=204)
        else:
            return HttpResponse(status=400)


class Solution():
    """_summary_
        print an array in recursive way
    """
    def printArray(self,arr,idx)->None:
        if idx == len(arr):
            return
        print(arr[idx])
        self.printArray(arr,idx+1)

n = int(input())
arr = []
for i in range(n):
    arr.append(int(input()))
Solution().printArray(arr,0)


import logging
from asyncio import (
    AbstractEventLoop,
)
from typing import (
    NoReturn,
)

from aiomisc.entrypoint import (
    Entrypoint,
)
from aiomisc.utils import (
    create_default_event_loop,
)
from cached_property import (
    cached_property,
)

logger = logging.getLogger(__name__)

class EntrypointLauncher:
    """EntryPoint Launcher class."""

    def __init__(self, services: tuple):
        self.services = services

    def launch(self) -> NoReturn:
        """Launch a new execution and keeps running forever..

        :return: This method does not return anything.
        """
        logger.info("Starting Discovery...")
        try:
            self.loop.run_until_complete(self.entrypoint.__aenter__())
            logger.info("Discovery is up and running!")
            self.loop.run_forever()
        except KeyboardInterrupt:  # pragma: no cover
            logger.info("Stopping discovery...")
        finally:
            self.graceful_shutdown()

    def graceful_shutdown(self, err: Exception = None) -> None:
        """Shutdown the services execution gracefully.

        :return: This method does not return anything.
        """
        self.loop.run_until_complete(self.entrypoint.graceful_shutdown(err))

    @cached_property
    def entrypoint(self) -> Entrypoint:
        """Entrypoint instance.

        :return: An ``Entrypoint`` instance.
        """

        return Entrypoint(*self.services, loop=self.loop)  # pragma: no cover

    @cached_property
    def loop(self) -> AbstractEventLoop:
        """Create the loop.

        :return: An ``AbstractEventLoop`` instance.
        """
        return create_default_event_loop()[0]  # pragma: no cover


import os
import pickle
import functools
from glob import glob,iglob
from math import factorial
import numpy as np
import pandas as pd
from scipy.stats import rankdata
from scipy.optimize import minimize
import torch
from tqdm import tqdm

##### Helper functions ######
def m_r(m,r):
    return factorial(m)/factorial(m-r)

def tr_te_indices(n, tr_proportion, seed=9282 ):
    '''
        Get two logical vectors for indexing train/test points.
        Return (tr_ind, te_ind)
        From https://github.com/wittawatj/interpretable-test
    '''
    rand_state = np.random.get_state()
    np.random.seed(seed)

    Itr = np.zeros(n, dtype=bool)
    tr_ind = np.random.choice(n, int(tr_proportion*n), replace=False)
    Itr[tr_ind] = True
    Ite = np.logical_not(Itr)

    np.random.set_state(rand_state)
    return (Itr, Ite)

def subsample_ind(n, k, seed=28):
    '''
    Return a list of indices to choose k out of n without replacement
    From https://github.com/wittawatj/interpretable-test
    '''
    rand_state = np.random.get_state()
    np.random.seed(seed)

    ind = np.random.choice(n, k, replace=False)
    np.random.set_state(rand_state)
    return ind

def multiple_testing_correction(p_values,alpha=0.01,method='Benjamini-Hochberg'):
    '''
    If required. Not needed in the current algorithms.
    '''
    if method=='Bonferroni':
        return np.where(p_values*len(p_values) <= alpha)[0]
    elif method == 'Benjamini-Hochberg':
        ranks = rankdata(p_values)
        correction_factor = (ranks/len(ranks))*alpha
        return np.where(p_values <= correction_factor)[0]
    else:
        raise NotImplementedError("Method not implemented.")

def prune_features(w,feature_percentage):
    cutoff = np.percentile(w.numpy(),100*(1-feature_percentage))
    return np.where(w>cutoff)[0]

def getRadiomicFeatures(data,pats_resp,times_uni = [0,60,120]):

    # Get radiomic pretreatment features for pats
    rad_feat = data.iloc[:, list(data.columns).index('ORIGINAL_SHAPE_ELONGATION_WHOLE'):list(data.columns).index(
        'SERIESDESCRIPTION_CYSTIC')].drop([
        'SERIESDESCRIPTION_CORE', 'ANNOTATION_CORE'], axis=1)
    rad_feat['pnoc_case'] = data['pnoc_case'].astype(str)
    rad_feat['time_days'] = data['time_days']
    rad_feat_pre = rad_feat[rad_feat['time_days']==0]
    inds_2 = [i +1 for i in list(np.where(rad_feat['time_days']==0)[0])]
    rad_feat_t2 = rad_feat.iloc[inds_2,:]

    # Now get pats with labels
    rad_feat_pre.set_index('pnoc_case', inplace = True)
    rad_feat_pre = rad_feat_pre.loc[pats_resp]
    rad_feat_t2.set_index('pnoc_case', inplace = True)
    rad_feat_t2 = rad_feat_t2.loc[pats_resp]

    # Check features
    feats_cat = []
    all_cats = []
    feats_orig = []
    for f in rad_feat_pre.columns:
        this_feat_cat = f.split('_')[0]
        all_cats.append(this_feat_cat)
        if this_feat_cat not in feats_cat:
            if this_feat_cat not in ['time','responder']:
                feats_cat.append(this_feat_cat)

        if this_feat_cat == 'ORIGINAL':
            feats_orig.append(f)
    feats_keep = list(rad_feat_pre.columns[rad_feat_pre.isna().sum()<8])

    # For now keep only "Original" features
    rad_feat_pre = rad_feat_pre[feats_keep]
    rad_feat_t2 = rad_feat_t2[feats_keep]

    # Only 31 (7 positive) pats with label and radiomic features - if thresh = 365
    # thresh = 90: 15 positive, 16 negative
    rad_feat_pre = rad_feat_pre.dropna()
    rad_feat_pre.drop('time_days', axis = 1, inplace = True)

    time_t2 = rad_feat_t2['time_days']
    rad_feat_t2.drop('time_days', axis = 1, inplace = True)
    rad_feat_t2.columns = [c+'_t2' for c in rad_feat_t2.columns]
    rad_feat_t2 = rad_feat_t2.loc[rad_feat_pre.index]
    time_t2 = time_t2.loc[rad_feat_t2.index]

    inds_3 = [i +2 for i in list(np.where(rad_feat['time_days']==0)[0])]
    rad_feat_t3 = rad_feat.iloc[inds_3,:]
    rad_feat_t3.set_index('pnoc_case', inplace = True)
    rad_feat_t3 = rad_feat_t3.loc[rad_feat_t2.index]

    # Check for dublicate patients
    rad_feat_t3.index.duplicated(keep='last')
    rad_feat_t3 = rad_feat_t3[~rad_feat_t3.index.duplicated(keep='last')]
    rad_feat_t3 = rad_feat_t3[feats_keep]
    time_t3 = rad_feat_t3['time_days']
    rad_feat_t3.drop('time_days', axis = 1, inplace = True)
    rad_feat_t3.columns = [c+'_t3' for c in rad_feat_t3.columns]
    rad_feat_t3 = rad_feat_t3.loc[rad_feat_pre.index]

    inds_4 = [i +3 for i in list(np.where(rad_feat['time_days']==0)[0])]
    rad_feat_t4 = rad_feat.iloc[inds_4,:]
    rad_feat_t4.set_index('pnoc_case', inplace = True)
    rad_feat_t4 = rad_feat_t4.loc[rad_feat_t2.index]
    rad_feat_t4.index.duplicated(keep='last')
    rad_feat_t4 = rad_feat_t4[~rad_feat_t4.index.duplicated(keep='last')]
    rad_feat_t4 = rad_feat_t4[feats_keep]
    time_t4 = rad_feat_t4['time_days']
    rad_feat_t4.drop('time_days', axis = 1, inplace = True)
    rad_feat_t4.columns = [c+'_t4' for c in rad_feat_t4.columns]
    rad_feat_t4 = rad_feat_t4.loc[rad_feat_pre.index]

    # Get the times
    time_0 = pd.Series(index = time_t2.index, data = np.zeros((len(time_t2.index),)))
    times = pd.concat([time_0,time_t2,time_t3,time_t4],axis=1)

    # Want uniform time grid - interpolate
    rad_feat_all = pd.concat([rad_feat_pre,rad_feat_t2,rad_feat_t3,rad_feat_t4],axis = 1)

    # Loop over all patients
    rad_feat_all_uni = pd.DataFrame(index = rad_feat_all.index)
    for p in tqdm(times.index):

        # for each patient interpolate the radiomic features
        for c in rad_feat_pre.columns:
            this_cols = [c+k for k in ['','_t2','_t3','_t4']]

            #loop over time points
            for t in times_uni:
                time_interp = times.loc[p].values
                val_interp  = rad_feat_all.loc[p,this_cols].values
                inds_keep = ~np.isnan(val_interp)

                rad_feat_all_uni.loc[p,c+'_'+str(t)] =\
                    np.interp(t,time_interp[inds_keep],val_interp[inds_keep])

    rad_feat_t2uni = rad_feat_all_uni.loc[:,]

    # rad_feat_ratio = pd.DataFrame(index = rad_feat_t2.index, data = rad_feat_t2uni.values/rad_feat_pre.values,
    #                               columns = [c+'_ratio' for c in rad_feat_pre.columns])
    # rad_feat_ratio.fillna(0, inplace=True)
    # inf_cols = rad_feat_ratio.columns[rad_feat_ratio.isin([np.inf, -np.inf]).sum()>0]
    # for c in inf_cols:
    #     this_max =rad_feat_ratio.loc[rad_feat_ratio[c] != np.inf, c].max()
    #     rad_feat_ratio[c].replace(np.inf, this_max, inplace=True)
    #
    # rad_feat_diff = pd.DataFrame(index = rad_feat_t2.index, data = rad_feat_t2.values-rad_feat_pre.values,
    #                               columns = [c+'_dif' for c in rad_feat_pre.columns])
    # rad_feat = pd.concat([rad_feat_pre,rad_feat_t2,rad_feat_ratio,rad_feat_diff],axis = 1)
    return rad_feat_all_uni.copy()

def getUniquePats(df_res_sub,thresh):
    pats_resp = np.unique([np.int(p[:2]) for p in df_res_sub.index])
    ids_keep = []
    resp = []
    for p in pats_resp:
        try:
            resp.append(df_res_sub.loc[str(p)+'_LATE','responder'+str(thresh)])
            ids_keep.append(str(p)+'_LATE')
        except:
            resp.append(df_res_sub.loc[str(p) + '_EARLY', 'responder'+str(thresh)])
            ids_keep.append(str(p) + '_EARLY')
    pats_resp  = [str(p) for p in pats_resp]

    return pats_resp,ids_keep,resp

##### Data loaders ######
def load_lgg_radiomic(file_path,label='ATRX'):
    # Load data
    data = pd.read_csv(os.path.join(file_path,'radiomic_feat.csv'),index_col=0)
    data = data.dropna(axis=1)
    data[data=='#DIV/0!'] = np.nan
    data = data.dropna(axis=0).astype(float)

    # Now do everything else
    if label=='H0':
        XY = data.values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        labels = pd.read_csv(os.path.join(file_path,'labels_mut.csv'),index_col=0)
        overlap = list(set(data.index).intersection(set(labels.index)))
        labels_subset = labels.loc[overlap]
        X_idx = labels_subset[labels_subset[label]==1].index
        Y_idx = labels_subset[labels_subset[label]==0].index
        X = data.loc[X_idx].values
        Y = data.loc[Y_idx].values
    feature_names = data.columns.values
    return X,Y,feature_names

def load_lgg_expression(file_path,label='ATRX'):
    # Load data
    data = pd.read_csv(os.path.join(file_path,'expr.csv'),index_col=0)
    data = data.dropna(axis=1)
    data[data=='#DIV/0!'] = np.nan
    data = data.dropna(axis=0).astype(float)

    # Log transform the counts data as usual
    tmp = np.log(data.values+1)
    # Every sample should have mean 0 and std 1 over the genes
    tmp = (tmp-tmp.mean(axis=1,keepdims=True))/tmp.std(axis=1,keepdims=True)
    data = pd.DataFrame(data=tmp,index=data.index,columns=data.columns)

    # Now do everything else
    if label=='H0':
        XY = data.values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        labels = pd.read_csv(os.path.join(file_path,'labels_mut.csv'),index_col=0)
        overlap = list(set(data.index).intersection(set(labels.index)))
        labels_subset = labels.loc[overlap]
        X_idx = labels_subset[labels_subset[label]==1].index
        Y_idx = labels_subset[labels_subset[label]==0].index
        X = data.loc[X_idx].values
        Y = data.loc[Y_idx].values
    feature_names = data.columns.values
    return X,Y,feature_names

def load_karolinska(fname):
    with open(fname, 'rb') as f:
        loaded = pickle.load(f)
    return loaded

def load_nips(file_path):
    with open(file_path, 'rb') as f:
        loaded = pickle.load(f)
    X = loaded['P']
    Y = loaded['Q']
    words = loaded['words']
    n_min = min(X.shape[0], Y.shape[0])
    X = X[:n_min, :]
    Y = Y[:n_min, :]
    assert(X.shape[0] == Y.shape[0])
    return X,Y,words

def load_adni_radiomic(file_path,label='test'):
    data = pd.read_csv(os.path.join(file_path,'3DradiomicFeatures_HC_lr.csv'),index_col=0)
    labels = pd.read_csv(os.path.join(file_path,'labels.csv'),index_col=0)
    data['label'] = labels.label
    data_subset = data[~data.label.isna()]
    if label == 'H0':
        XY = data_subset.drop('label',axis=1).values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        X = data_subset[data_subset.label==0].drop('label',axis=1).values
        Y = data_subset[data_subset.label==1].drop('label',axis=1).values
    feature_names = data.drop('label',axis=1).columns.values
    return X,Y,feature_names

def load_adni_images(file_path,view='axial',label='test'):
    data_files = glob(os.path.join(file_path,'2Dimages',view,'*.npy'))
    labels = pd.read_csv(os.path.join(file_path,'labels.csv'),index_col=0)
    data_files_filtered = [f for f in data_files if f.split('/')[-1].split('.')[0] in labels.index]
    data = pd.DataFrame({f.split('/')[-1].split('.')[0]:np.load(f,allow_pickle=True).flatten() for f in data_files_filtered}).T
    data_shape = np.load(data_files_filtered[0],allow_pickle=True).shape
    data['label'] = labels.label
    data_subset = data[~data.label.isna()]
    if label == 'H0':
        XY = data_subset.drop('label',axis=1).values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        X = data_subset[data_subset.label==0].drop('label',axis=1).values
        Y = data_subset[data_subset.label==1].drop('label',axis=1).values
    return X,Y,data_shape

def pickle_driams(file_path,species='Escherichia coli',drug='Ceftriaxone'):
    if not os.path.exists(os.path.join(file_path,f'driams_{species}_{drug}.pkl')):
        labels = pd.read_csv(os.path.join(file_path,'2018_strat.csv'),index_col=1)
        labels_species = labels[labels.species==species]
        final_labels = labels_species[labels_species[drug].isin(['S','R'])]
        all_files = glob(os.path.join(file_path,'2018','*.txt'))
        relevant_files = [f for f in all_files if f.split('/')[-1].split('.')[0] in final_labels.index.values]
        data = pd.DataFrame(columns=np.arange(6000))
        for f in relevant_files:
            data.loc[f.split('/')[-1].split('.')[0]] = pd.read_csv(f,comment='#',sep=' ',dtype=np.float64,low_memory=False).binned_intensity.values
        data['label'] = final_labels[drug]
        with open(os.path.join(file_path,f'driams_{species}_{drug}.pkl'),'wb') as f:
            pickle.dump(data, f)

def load_driams(file_path,species='Escherichia coli',drug='Ceftriaxone',label='test'):
    with open(os.path.join(file_path,f'driams_{species}_{drug}.pkl'),'rb') as f:
        data = pickle.load(f)
    if label == 'H0':
        XY = data.drop('label',axis=1).values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        X = data[data.label=='S'].drop('label',axis=1).values
        Y = data[data.label=='R'].drop('label',axis=1).values
    return X,Y

def load_scanpy(file_path,label='H0'):
    data = pd.read_csv(os.path.join(file_path,'pbmc3k_processed.csv'),index_col=0)
    if label == 'H0':
        XY = data.drop('label',axis=1).values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        X = data[data.label==label].drop('label',axis=1).values
        Y = data[data.label!=label].drop('label',axis=1).values
    feature_names = data.drop('label',axis=1).columns.values
    return X,Y,feature_names

def load_pnoc001_radiomic(file_path, label='test',thresh = 90,times_uni = [0,60,120]):

    # load data
    data = pd.read_excel(file_path)
    df_res_sub = pd.read_csv('/Users/sbrueningk/Desktop/MMD/data/PNOC/fitres.csv', index_col=0)

    # Get response label
    df_res_sub['responder' + str(thresh)] = (df_res_sub['tc'] >= thresh).astype(int)

    # Get pats - prevent double instances
    pats_resp, ids_keep, resp = getUniquePats(df_res_sub, thresh)
    df_res_sub = df_res_sub.loc[ids_keep]
    df_res_sub['pnoc_case'] = pats_resp
    df_res_sub.set_index('pnoc_case', inplace=True)

    # get radiomic features
    df_radfeat = getRadiomicFeatures(data, pats_resp, times_uni=times_uni)
    df_res_sub = df_res_sub.loc[df_radfeat.index]

    # Prediction
    labels       = df_res_sub['responder' + str(thresh)]
    pats_nonresp = list(labels[labels==0].index)
    pats_resp    = list(labels[labels==1].index)

    data['label'] = labels.label
    data_subset = data[~data.label.isna()]
    if label == 'H0':
        XY = data_subset.drop('label',axis=1).values
        np.random.shuffle(XY)
        X = XY[:int(np.floor(XY.shape[0]/2))]
        Y = XY[int(np.ceil(XY.shape[0]/2)):]
    else:
        X = data_subset[data_subset.label==0].drop('label',axis=1).values
        Y = data_subset[data_subset.label==1].drop('label',axis=1).values
        X = df_radfeat.loc[pats_nonresp]
        Y = df_radfeat.loc[pats_resp]

    feature_names = X.columns.values

    return X, Y, feature_names

def load_pnoc001PI3K_radiomic(file_path, label='test',thresh = 90,times_uni = [0,60,120]):

    # load data
    data = pd.read_excel(file_path)
    df_res_sub = pd.read_csv('/Users/sbrueningk/Desktop/MMD/data/PNOC/fitres.csv', index_col=0)

    # Get response label
    df_res_sub['responder' + str(thresh)] = (df_res_sub['tc'] >= thresh).astype(int)

    # Get pats - prevent double instances
    pats_resp, ids_keep, resp = getUniquePats(df_res_sub, thresh)
    df_res_sub = df_res_sub.loc[ids_keep]
    df_res_sub['pnoc_case'] = pats_resp
    df_res_sub.set_index('pnoc_case', inplace=True)

    # get radiomic features
    df_radfeat = getRadiomicFeatures(data, pats_resp, times_uni=times_uni)
    df_res_sub = df_res_sub.loc[df_radfeat.index]

    # Prediction
    labels = df_res_sub['responder' + str(thresh)]
    pats_nonresp = list(labels[labels==0].index)
    pats_resp = list(labels[labels==1].index)
    X = df_radfeat.loc[pats_nonresp]
    Y = df_radfeat.loc[pats_resp]
    feature_names = X.columns.values

    return X, Y, feature_names

##### Optimization ######
#### SCIPY #####
def find_weights_sp(X,Y,func_z,max_iter=400,lam=1e-1,ftol=2.220446049250313e-09,kernel=None,verbose=True,**kwargs):
    def loss_fn(w,X,Y,func_z,lam,kernel):
        w = torch.from_numpy(w).requires_grad_()
        if kernel is None:
            loss = -func_z(w*X,w*Y) + lam*torch.abs(w).sum()
        else:
            loss = -func_z(w*X,w*Y,kernel) + lam*torch.abs(w).sum()
        loss.backward()
        return loss.detach().cpu().numpy(), w.grad.detach().cpu().numpy()

    X = torch.from_numpy(X)
    Y = torch.from_numpy(Y)

    # nx, d = X.shape
    # w0 = (1./d)*np.ones(d)
    w0 = np.ones(X.shape[1])

    # normalise lambda by number of features.
    # This way the chosen regularisation is independent of the number of features.
    lam_norm = lam/X.shape[1]

    loss_fn_partial = functools.partial(loss_fn,X=X,Y=Y,func_z=func_z,lam=lam_norm,kernel=kernel)

    res = minimize(loss_fn_partial, w0, method='L-BFGS-B', jac=True, options={'maxiter':max_iter,'iprint': 10 if verbose else -1,'ftol':ftol})

    # optimization info
    info = {'weights': np.abs(res['x']),'final_loss': res['fun'], 'success':res['success']}
    return info

#### Torch ####
def find_weights_torch(X,Y,func_z,max_iter=400,lam=1e-1,step_size=1e-2,batch_proportion=1.0,ftol=1e-3,kernel=None,verbose=True):

    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    w = torch.ones(X.shape[1],requires_grad=True).to(device)
    X = torch.from_numpy(X).to(device)
    Y = torch.from_numpy(Y).to(device)

    # normalise lambda by number of features.
    # This way the chosen regularisation is independent of the number of features.
    lam_norm = lam/X.shape[0]

    if kernel is None:
        loss = lambda X,Y,w,lam: -func_z(w*X,w*Y) + lam*torch.abs(w).sum()
    else:
        loss = lambda X,Y,w,lam,kernel: -func_z(w*X,w*Y,kernel) + lam*torch.abs(w).sum()

    # //////// run gradient descent //////////////

    optimizer = torch.optim.SGD([w],lr=step_size,momentum=0.9,nesterov=True)
    # optimizer = torch.optim.Adam([w],lr=step_size)
    # optimizer = torch.optim.RMSprop([w],lr=step_size)
    # optimizer = torch.optim.LBFGS([w],lr=step_size)
    for t in range(max_iter):
        ind = np.random.choice(nx, min(int(batch_proportion*nx), nx), replace=False)
        if kernel is None:
            l = loss(X[ind, :],Y[ind, :],w,lam_norm)
        else:
            l = loss(X[ind, :],Y[ind, :],w,lam_norm,kernel)

        def closure(ind=ind):
            optimizer.zero_grad()
            # stochastic gradient descent
            if kernel is None:
                l = loss(X[ind, :],Y[ind, :],w,lam_norm)
            else:
                l = loss(X[ind, :],Y[ind, :],w,lam_norm,kernel)
            l.backward()
            return l
        optimizer.step(closure)

        # Project
        # w.data = w.data*(d/torch.sum(w.data))
        # w.data = torch.clamp(w.data,min=0.0) #torch.max(torch.stack([torch.zeros_like(w.data), w.data],axis=0),axis=0).values
        w.data = torch.abs(w.data)

        # record objective values
        if kernel is None:
            Z,l_new = func_z(w*X[ind, :], w*Y[ind, :]).detach().cpu().numpy(),loss(X[ind, :],Y[ind, :],w,lam_norm).detach().cpu().numpy()
        else:
            Z,l_new = func_z(w*X[ind, :],w*Y[ind, :],kernel).detach().cpu().numpy(),loss(X[ind, :],Y[ind, :],w,lam_norm,kernel).detach().cpu().numpy()
        # weights[t] = w.detach().cpu().numpy()

        # check the change of the objective values
        rel_change = abs((l_new-l.detach().cpu().numpy())/l.detach().cpu().numpy())
        if rel_change <= ftol:
            final_t = t
            break
        else:
            final_t = t

        # Print update
        if verbose and t % 10 == 0:
            print(f'Step {t+1} of {max_iter}. Loss: {l_new}. MMD: {Z}. relative change: {rel_change}')

    # optimization info
    info = {'weights': w.detach().cpu().numpy(), 'final_loss': l_new, 'final_MMD': Z, 'success':True}
    return info


import math
from .monster_type import MonsterType
from utils.misc import is_in_roi

class MonsterRule:

    def __init__(self,
                 names:         list[str] = None,
                 monster_types: list[MonsterType] = None,
                 auras:         list[str] = None,
                 boss_id:       int = None,
                 mob_number:    int = None,
                 time_out:      float = 6.0,
                 max_distance:  float = None,
                 area_tether:   tuple[float, float] = None,
                 boundary:      list[int] = None,
                ):
        self.names = names
        self.monster_types = monster_types
        self.auras = auras
        self.boss_id = boss_id
        self.mob_number = mob_number
        self.time_out = time_out
        self.max_distance = max_distance
        self.area_tether = area_tether
        self.boundary = boundary

    def evaluate_monster(self, monster: dict, min_score: int = 0) -> int:
        rules_met = 0
        if monster is not None and type(monster) is dict:
            m_types = monster["type"].split(", ") if type(monster["type"]) is str else []
            if self.names is not None and any(monster["name"].startswith(startstr) for startstr in self.names):
                rules_met += 1
            if self.monster_types is not None:
                for monster_type in self.monster_types:
                    if any(monster_type == mtype for mtype in m_types):
                        rules_met += 1
                        break
            # Not working corectly at the moment, only use for conviction
            if self.auras is not None:
                for aura in self.auras:
                    if any(aura in state for state in monster["state_strings"]):
                        rules_met += 1
                        break
            if self.boss_id is not None and "boss_id" in monster and self.boss_id == monster["boss_id"]:
                rules_met += 1
            if self.mob_number is not None and "mob_number" in monster and self.mob_number == monster["mob_number"]:
                rules_met += 1
            if self.max_distance is not None:
                if self.area_tether is not None:
                    if math.dist(self.area_tether, monster["position_area"]) > self.max_distance:
                        return 0
                elif monster["dist"] > self.max_distance:
                    return 0
        score = rules_met + min_score if rules_met > 0 else 0
        return score


# EoM - EMV (Ease of Movement)
# https://en.wikipedia.org/wiki/Ease_of_movement

# Bir varlığın fiyat değişikliğini hacmiyle ilişkilendirir
#  ve bir eğilimin gücünü değerlendirmek için özellikle yararlıdır.

# Argümanlar:
#  high(pandas.Series): veri kümesi 'Yüksek' sütunu.
#  low(pandas.Series): veri kümesi 'Düşük' sütunu.
#  volume(pandas.Series): veri kümesi 'Volume' sütunu.
#  window(int): n periyodu.
#  fillna(bool): True ise, nan değerlerini doldur.

import pandas as pd
from _utilities import IndicatorMixin

class EaseOfMovementIndicator(IndicatorMixin):
    def __init__(
        self,
        high: pd.Series,
        low: pd.Series,
        volume: pd.Series,
        window: int = 14,
        fillna: bool = False,
    ):
        self._high = high
        self._low = low
        self._volume = volume
        self._window = window
        self._fillna = fillna
        self._run()

    def _run(self):
        self._emv = (
            (self._high.diff(1) + self._low.diff(1))
            * (self._high - self._low)
            / (2 * self._volume))

        self._emv *= 100000000

    def ease_of_movement(self) -> pd.Series:
        emv = self._check_fillna(self._emv, value=0)
        return pd.Series(emv, name=f"eom_{self._window}")

    # sinyal:
    def sma_ease_of_movement(self) -> pd.Series:
        min_periods = 0 if self._fillna else self._window
        emv = self._emv.rolling(self._window, min_periods=min_periods).mean()
        emv = self._check_fillna(emv, value=0)
        return pd.Series(emv, name=f"sma_eom_{self._window}")


import os
import pandas as pd
import numpy as np
import argparse
import random
import tensorflow as tf
import keras.backend as K
from time import time
from tqdm import tqdm
from deepctr.feature_column import SparseFeat, DenseFeat, get_feature_names, VarLenSparseFeat
from sklearn.preprocessing import LabelEncoder, MinMaxScaler
from tensorflow.python.keras.optimizers import Adam, Adagrad
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import KFold
from tensorflow.python.keras.models import save_model, load_model
from sklearn.preprocessing import label_binarize
from model import AutoInt_, DCN_

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
print(BASE_DIR)

parser = argparse.ArgumentParser(description='seed')
parser.add_argument("--k", metavar='seed', type=int, default=0)
args = parser.parse_args()
k = args.k

seed = k
random.seed(seed)
os.environ['PYTHONHASHSEED'] = str(seed)
np.random.seed(seed)
tf.set_random_seed(seed)

os.environ["CUDA_VISIBLE_DEVICES"] = "0"

config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)

epochs = 80
batch_size = 9192
embedding_dim = 32
n_classes = 10
score_weights = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]

# 读取训练集
BEHAVIOR_PATH = '/opt/data/traindata/history_behavior_data/'
DATE_PATH = [BEHAVIOR_PATH + i for i in os.listdir(BEHAVIOR_PATH)]
DATE_PATH = sorted(DATE_PATH)
BEHAVIOR_PATH_ = [i + '/' + os.listdir(i)[0] for i in DATE_PATH]

history_behavior_list = []
for i in tqdm(range(len(BEHAVIOR_PATH_))):
    history_behavior = pd.read_csv(BEHAVIOR_PATH_[i], sep='\t')
    history_behavior_list.append(history_behavior)

history_behavior_df = pd.concat(history_behavior_list)
del history_behavior_list

# 训练集采样
train = history_behavior_df
train1 = train[train['watch_label'] != 0]
print(len(train1))
train2 = train[train['watch_label'] == 0].sample(frac=0.1, random_state=k).reset_index(drop=True)
print(len(train2))
train = pd.concat([train1, train2])
del train1, train2

# 读取测试集
test = pd.read_csv('/opt/data/testdata/test.csv')
test['pt_d'] = '20210503'
data = pd.concat([train, test])

# 视频特征拼接
video_features = pd.read_pickle('/opt/feature/video_features.pkl')
data = pd.merge(data, video_features, on='video_id', how='left')

# 日期特征
data['pt_d'] = data['pt_d'].astype('str')
data['pt_d'] = data['pt_d'].apply(lambda x: x[:4] + '-' + x[4:6] + '-' + x[6:])
data['pt_d'] = pd.to_datetime(data['pt_d'])
data['day'] = (data['pt_d'] - data['video_release_date']).dt.days

# w2v特征
user_features = pd.read_pickle('/opt/feature/user_video_w2v.pkl')
data = pd.merge(data, user_features, on='user_id', how='left')

# 用户属性特征
user_features = pd.read_csv('/opt/data/traindata/user_features_data/user_features_data.csv', sep='\t')
data = pd.merge(data, user_features, on='user_id', how='left')

# 特征数据预处理
data[['video_year', 'video_month']] = data[['video_year', 'video_month']].fillna(0)
data[['video_year', 'video_month']] = data[['video_year', 'video_month']].astype('int32')

target = ['watch_label', 'is_share']
sparse_features = ['province', 'city', 'device_name', 'user_id', 'video_id', 'video_year', 'video_month', 'gender', 'city_level', 'age']
varlen_sparse_features = ['video_tags', 'video_director_list', 'video_actor_list', 'video_second_class']
dense_features = ['video_score', 'video_duration',  'day']

print(len(dense_features))
print(len(sparse_features))
data[dense_features] = data[dense_features].fillna(-1)
scaler = MinMaxScaler()
data[dense_features] = scaler.fit_transform(data[dense_features])
dense_features.extend([f'user_id_video_id_emb_{i}' for i in range(16)])

maxlen_dict = {'video_tags': 81, 'video_director_list': 11, 'video_actor_list': 104, 'video_second_class': 9}
vocab_dict = {'video_tags': 21427, 'video_director_list': 28036, 'video_actor_list': 78291, 'video_second_class': 145}

for f in varlen_sparse_features:
    data[f] = data[f].fillna(0)
    data[f] = data[f].apply(lambda x: [0] * maxlen_dict[f] if x == 0 else x)

train = data[data['pt_d'] <= '2021-05-02']
test = data[data['pt_d'] == '2021-05-03']
print(len(test))
del data

# 构造输入
fixlen_feature_columns = [SparseFeat(feat, vocabulary_size=max(train[feat].max(), test[feat].max()) + 1, embedding_dim=embedding_dim)
                          for feat in sparse_features] + [DenseFeat(feat, 1) for feat in dense_features]

varlen_feature_columns = [VarLenSparseFeat(SparseFeat(feat, vocabulary_size=vocab_dict[feat],
                                                      embedding_dim=embedding_dim), maxlen=maxlen_dict[feat], combiner='mean', weight_name=None) for feat in varlen_sparse_features]

dnn_feature_columns = fixlen_feature_columns + varlen_feature_columns
linear_feature_columns = fixlen_feature_columns + varlen_feature_columns

feature_names = get_feature_names(linear_feature_columns + dnn_feature_columns)

train_model_input = {name: train[name] for name in feature_names}
test_model_input = {name: test[name] for name in feature_names}

for feat in tqdm(varlen_sparse_features):
    train_model_input[feat] = np.asarray(train_model_input[feat].to_list()).astype(np.int32)
    test_model_input[feat] = np.asarray(test_model_input[feat].to_list()).astype(np.int32)

y_binary = label_binarize(train['watch_label'], classes=range(n_classes))
s = train['watch_label'].value_counts().to_dict()
label_num_list = [s[i] for i in sorted(s.keys())]
total_sample_num = sum(label_num_list)

def multi_category_focal_loss(y_true, y_pred):
    gamma = 2.0
    epsilon = 1.e-7

    y_true = tf.cast(y_true, tf.float32)
    y_pred = tf.cast(y_pred, tf.float32)

    classes_weight = [total_sample_num / label_num for label_num in label_num_list]
    classes_weight_norm = [weight / sum(classes_weight) for weight in classes_weight]
    print(classes_weight_norm)
    classes_weight_norm = tf.cast(classes_weight_norm, tf.float32)
    alpha = tf.expand_dims(classes_weight_norm, 1)

    y_pred = tf.clip_by_value(y_pred, epsilon, 1. - epsilon)
    pt = tf.multiply(y_true, y_pred) + tf.multiply(1 - y_true, 1 - y_pred)
    cross_entropy_loss = -K.log(pt)
    weight = tf.pow(tf.subtract(1., pt), gamma)
    focal_loss = tf.matmul(tf.multiply(weight, cross_entropy_loss), alpha)

    return focal_loss

# 模型训练
epochs = 5
model = DCN_(linear_feature_columns, dnn_feature_columns, task='multiclass')
model.compile("adagrad", multi_category_focal_loss)

history = model.fit(train_model_input, y_binary, batch_size=batch_size, epochs=epochs, verbose=1)
# save_model(model, 'dcn_watch' + str(k) + '.h5')
# model.save_weights('dcn_watch_' + str(k) + '.h5')
if not os.path.exists('/opt/sub/'):
    os.makedirs('/opt/sub/')

temp = model.predict(test_model_input, batch_size=batch_size * 4)
np.save('/opt/sub/dcn_watch_' + str(k) + '.npy', temp)


from curses import *
RED = COLOR_RED
BLUE = COLOR_BLUE
CYAN = COLOR_CYAN
GREEN = COLOR_GREEN
WHITE = COLOR_WHITE
BLACK = COLOR_BLACK
YELLOW = COLOR_YELLOW
MAGENTA = COLOR_MAGENTA
GREY = 8

BRIGHT_GREEN = 10
BRIGHT_RED = 12
BRIGHT_BLUE = 9
BRIGHT_CYAN = 11
BRIGHT_WHITE = 15
BRIGHT_YELLOW = 14
BRIGHT_MAGENTA = 13

BACKGROUND = BLACK


N = 9
w = 595.0
h = 842.0
rows = 3
cols = 2
padding = 20.0
margin = 30.0

import cairo
import math
import sys

output = sys.argv[1]
inp = sys.stdin.read().split()
grids = []
for i in xrange(len(inp)/9):
  grids.append([map(int,l) for l in inp[i*9:(i+1)*9]])
surface = cairo.PDFSurface(output, w, h)

# background
def get_ctx():
  return cairo.Context(surface)
ctx = get_ctx()
ctx.set_source_rgb(1,1,1)
ctx.rectangle(0,0,w,h)
ctx.fill()

def line(x1,y1,x2,y2):
  ctx.move_to(x1,y1)
  ctx.line_to(x2,y2)

def draw(x1,y1,sz,grid):
  ctx.set_line_width(2)
  ctx.set_source_rgb(0, 0, 0)
  ctx.rectangle(x1, y1, sz, sz)
  ctx.stroke()

  ctx.set_line_width(0.1)
  ctx.set_source_rgb(0, 0, 0)
  for i in xrange(1,N):
    line(x1 + i*sz/N, y1, x1 + i*sz/N, y1 + sz)
    line(x1, y1 + i*sz/N, x1 + sz, y1 + i*sz/N)
  ctx.stroke()

  ctx.set_line_width(1.5)
  ctx.set_source_rgb(0, 0, 0)
  n = int(N**0.5)
  for i in xrange(n):
    for j in xrange(n):
      ctx.rectangle(x1 + i * sz/n, y1 + j * sz/n, sz/n, sz/n)
  ctx.stroke()

  ctx.set_font_size(sz/(N+4))
  for i in xrange(N):
    for j in xrange(N):
      if not grid[i][j]: continue
      txt = str(grid[i][j])
      ext = ctx.text_extents(txt)
      tw, th = ext[2], ext[3]
      ctx.move_to(x1 + j*sz/N + (sz/N-tw)/2 - 1, y1 + (i+1)*sz/N - (sz/N - th)/2)
      ctx.show_text(txt)

#
sz = min((w - (cols-1)*padding - 2*margin)/cols,
         (h - (rows-1)*padding - 2*margin)/rows)
xpad = (w - cols*sz - 2*margin)/(cols - 1)
ypad = (h - rows*sz - 2*margin)/(rows - 1)
y = margin
gi = 0
for i in xrange(rows):
  x = margin
  for j in xrange(cols):
    draw(x,y,sz,grids[gi])
    x += sz + xpad
    gi += 1
  y += sz + ypad

ctx.show_page()


def runSimulation(num_robots, speed, width, height, min_coverage, num_trials,
                  robot_type):
    """
    Runs NUM_TRIALS trials of the simulation and returns the mean number of
    time-steps needed to clean the fraction MIN_COVERAGE of the room.

    The simulation is run with NUM_ROBOTS robots of type ROBOT_TYPE, each with
    speed SPEED, in a room of dimensions WIDTH x HEIGHT.

    num_robots: an int (num_robots > 0)
    speed: a float (speed > 0)
    width: an int (width > 0)
    height: an int (height > 0)
    min_coverage: a float (0 <= min_coverage <= 1.0)
    num_trials: an int (num_trials > 0)
    robot_type: class of robot to be instantiated (e.g. StandardRobot or
                RandomWalkRobot)
    """
    times = []
    for trial in range(num_trials):
        room = RectangularRoom(width, height)
        robots = []

        for r in range(num_robots):
            robots.append(robot_type(room, speed))

        steps = 0
        while (room.getNumCleanedTiles()/room.getNumTiles()) < min_coverage:
            for roboto in robots:
                roboto.updatePositionAndClean()
            steps += 1

        times.append(steps)

    return (sum(times) / len(times))


"""
Module to analyze GLMs of widefield Ca2+ data
Lucas Pinto 2020, lucas.pinto@northwestern.edu
"""
#!/usr/bin/env python

# Libraries
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import lp_utils as utils
import deepdish as dd
import analyzeBehavior as behav
import mat73
from   scipy.io import loadmat
import pingouin as pg
import pandas as pd
import copy

wf_params = {
            'glm_comp_file'         : '/Users/lpinto/Dropbox/PintoEtAl2020_subtrial_inact/data/dffGLM_autoregr_model_comp_time.mat',
            'glm_summ_file'         : '/Users/lpinto/Dropbox/PintoEtAl2020_subtrial_inact/data/glmSummary_ROI_corr_autoRegr_time.mat',
            'glm_eg_file'           : '/Users/lpinto/Dropbox/PintoEtAl2020_subtrial_inact/data/dffGLM_time_ridge_ROI_autoRegr_ai3_20170201.mat',
            'mouse_eg_id'           : 1,
            'areaList'              : ['V1','mV2','PPC','RSC','mM2','aM2','M1'],
            'area_eg_idx_autoregr'  : [0, 3, 4, 6],
            'area_eg_idx_glm'       : [0, 7, 10, 13],
            'trial_idx_glm'         : range(933,983)
            }

# ==============================================================================
# load widefield model data
def load_glm(wf_params=wf_params):

    """
    glm = load_glm(wf_params=wf_params)
    takes optional wf_params dictionary, returns dictionary with GLM summary, comparison and single examples
    loaded from .mat files
    """

    glm                 = dict()
    glm['comp']         = loadmat(wf_params['glm_comp_file'], struct_as_record=True, squeeze_me=True)
    summ                = loadmat(wf_params['glm_summ_file'], struct_as_record=False, squeeze_me=True)
    glm['summ']         = summ['glmSumm']
    eg                  = mat73.loadmat(wf_params['glm_eg_file'])
    glm['eg']           = dict()
    glm['eg']['y']      = eg['dffFit']['bestpred_y'][:-2]
    glm['eg']['yhat']   = eg['dffFit']['bestpred_yhat'][:-2]
    glm['eg']['ROIlbl'] = utils.wf_ROIlbl_translate(eg['dffFit']['ROIlbl'][:-2])

    return glm

# ==============================================================================
# summarize glm results
def summarize_glm(glm=None):

    """
    glm_summ = summarize_glm(glm=None)
    takes glm dictionary (will load if None), returns dictionary with summary
    analysis of model performance and auto-regressive parameters
    """

    if glm is None:
        glm = load_glm()

    # set up
    glm_summ                  = dict()
    mouse_names               = utils.get_mouse_name(glm['comp']['recls'])
    glm_summ['mice']          = np.unique(mouse_names)
    num_mice                  = len(glm_summ['mice'])
    glm_summ['model_names']   = glm['comp']['model_names']
    num_models                = len(glm['comp']['model_names'])
    glm_summ['areaList']      = wf_params['areaList']
    num_areas                 = len(glm_summ['areaList'])
    accuracy                  = glm['comp']['accuracy'][:,:-2,:].flatten()
    glm_summ['accuracy_mice'] = np.zeros((num_mice,num_areas,num_models))
    glm_areas                 = utils.wf_ROIlbl_translate(glm['summ'].ROIlbl[0:-2])

    # compare accuracy
    area_mat  = np.stack([np.stack([glm_areas]*len(mouse_names),axis=0)]*num_models,axis=2).flatten()
    mouse_mat = np.stack([np.stack([mouse_names]*num_areas*2,axis=1)]*num_models,axis=2)[:,:,:,0].flatten()
    for iMouse, mouse in enumerate(glm_summ['mice']):
        for iArea, area in enumerate(glm_summ['areaList']):
            is_area  = area_mat == area
            is_mouse = mouse_mat == mouse
            this_mat = accuracy[np.logical_and(is_area,is_mouse)]
            this_mat = np.reshape(this_mat,(np.sum(np.array(mouse_names) == mouse),2,num_models))
            glm_summ['accuracy_mice'][iMouse,iArea,:] = np.mean(np.mean(this_mat,axis=0),axis=0)

    # remove just correlations model from analysis, irrelevant here
    is_valid                  = np.zeros((num_mice,num_areas,num_models)) == 0
    is_valid[:,:,1]           = False
    glm_summ['accuracy_mice'] = glm_summ['accuracy_mice'][is_valid].reshape(num_mice,num_areas,num_models-1)

    glm_summ['model_names']   = ['Task','Task + auto-regr.','Task + corr + auto-regr.']
    num_models                = len(glm_summ['model_names'])

    glm_summ['accuracy_mean'] = np.mean(glm_summ['accuracy_mice'],axis=0)
    glm_summ['accuracy_sem']  = np.std(glm_summ['accuracy_mice'],axis=0,ddof=1) / np.sqrt(num_mice)

    # stats
    # 2-way ANOVA with RM
    table = pd.DataFrame({'area' : np.repeat(range(num_areas), num_mice*num_models),
                          'mouse': np.tile(np.repeat(range(num_mice), num_models), num_areas),
                          'model': np.tile(range(num_models), num_mice*num_areas),
                          'acc'  : glm_summ['accuracy_mice'].flatten()})
    glm_summ['accuracy_anova_table']   = pg.rm_anova(dv='acc', within=['area','model'],subject='mouse',data=table)
    glm_summ['accuracy_posthoc_pvals'] = pg.pairwise_tukey(data=table,dv='acc',between='model')

    # timescales and towers
    glm_summ = analyze_timescales(glm,glm_summ)
    glm_summ = analyze_tower_weights(glm,glm_summ)

    return glm_summ

# ==============================================================================
# analyze autogressive coefficients
def analyze_timescales(glm,glm_summ):

    # extract relevant predictors
    num_mice   = len(glm_summ['mice'])
    num_areas  = len(glm_summ['areaList'])
    glm_areas  = utils.wf_ROIlbl_translate(glm['summ'].ROIlbl[0:-2])
    ispred_idx = np.array([glm['summ'].predLbls[iPred].find('auto') \
                           for iPred in range(np.size(glm['summ'].predLbls))])==0
    num_lags   = np.sum(ispred_idx)
    weights    = glm['summ'].weights[:-2,ispred_idx,:]
    glm_summ['acorr_weights']  = np.zeros((num_areas,num_lags,num_mice))
    glm_summ['taus']           = np.zeros((num_areas,num_mice))
    glm_summ['acorr_lags']     = np.arange(0,num_lags*.1,.1)
    glm_summ['acorr_xaxis']    = np.arange(0,num_lags*.1-.1,.01)
    glm_summ['acorr_fit_mice'] = np.zeros((num_areas,np.size(glm_summ['acorr_xaxis']),num_mice))
    glm_summ['acorr_fit_r2']   = np.zeros((num_areas,num_mice))

    # average over areas, normalize and fit exponentials
    for iArea, area in enumerate(glm_summ['areaList']):
        is_area = np.array(glm_areas) == area
        glm_summ['acorr_weights'][iArea,:,:] = np.mean(weights[is_area,:,:],axis=0)
        for iMouse in range(num_mice):
            glm_summ['acorr_weights'][iArea,:,iMouse] = glm_summ['acorr_weights'][iArea,:,iMouse] \
                                                        / glm_summ['acorr_weights'][iArea,0,iMouse]
            fit , _   = sp.optimize.curve_fit(exp_decay, glm_summ['acorr_lags'], \
                                              glm_summ['acorr_weights'][iArea,:,iMouse], maxfev=4000, bounds=[0.01, 1])
            glm_summ['taus'][iArea,iMouse]             = fit[0]
            glm_summ['acorr_fit_mice'][iArea,:,iMouse] = exp_decay(glm_summ['acorr_xaxis'],*fit)
            glm_summ['acorr_fit_r2'][iArea,iMouse]     = utils.fit_rsquare(glm_summ['acorr_weights'][iArea,:,iMouse], \
                                                                           exp_decay(glm_summ['acorr_lags'],*fit))

    # one-way ANOVA with RM for taus
    table = pd.DataFrame({'area' : np.repeat(range(num_areas), num_mice),
                          'mouse': np.tile(range(num_mice), num_areas),
                          'tau'  : glm_summ['taus'].flatten()})
    glm_summ['taus_anova_table'] = pg.rm_anova(dv='tau', within='area',subject='mouse',data=table)
    glm_summ['taus_anova_pval']  = glm_summ['taus_anova_table']['p-unc'].to_numpy()

    # avg fit
    glm_summ['acorr_weights_mean'] = np.mean(glm_summ['acorr_weights'],axis=2)
    glm_summ['acorr_weights_sem']  = np.std(glm_summ['acorr_weights'],axis=2,ddof=1) / np.sqrt(num_mice)
    glm_summ['acorr_fit_pred']     = np.zeros((num_areas,np.size(glm_summ['acorr_xaxis'])))
    for iArea in range(num_areas):
        fit , _ = sp.optimize.curve_fit(exp_decay, glm_summ['acorr_lags'], \
                                        glm_summ['acorr_weights_mean'][iArea,:], maxfev=4000, bounds=[0.01, 1])
        glm_summ['acorr_fit_pred'][iArea,:] = exp_decay(glm_summ['acorr_xaxis'],*fit)

    return glm_summ

# ==============================================================================
# analyze model coefficients related to towers
def analyze_tower_weights(glm,glm_summ,smooth_w=3):

    """
    glm_summ = analyze_tower_weights(glm,glm_summ,smooth_w=3)
    analyzes contralateral and \delta tower weights for each area
    called by summarize_glm. smooth_w is number of datapoints in sigma of a gaussian window
    for smoothing coefficients over lags
    """

    # extract relevant predictors
    towL_idx       = np.array([glm['summ'].predLbls[iPred].find('tow_L') \
                           for iPred in range(np.size(glm['summ'].predLbls))])==0
    towR_idx       = np.array([glm['summ'].predLbls[iPred].find('tow_R') \
                           for iPred in range(np.size(glm['summ'].predLbls))])==0
    delta_idx      = np.array([glm['summ'].predLbls[iPred].find('Delta') \
                           for iPred in range(np.size(glm['summ'].predLbls))])>0
    towL_weights   = glm['summ'].weights[:-2,towL_idx,:]
    towR_weights   = glm['summ'].weights[:-2,towR_idx,:]
    delta_weights  = glm['summ'].weights[:-2,delta_idx,:]

    # combine in ipsi and contra
    ROIlbl     = glm['summ'].ROIlbl[0:-2]
    glm_areas  = np.unique(utils.wf_ROIlbl_translate(ROIlbl))
    isR        = np.array([ROIlbl[iROI].find('-R') for iROI in range(len(ROIlbl))])>0
    isL        = ~isR

    hemR_towL_weights   = towL_weights[isR,:,:]
    hemR_towR_weights   = towR_weights[isR,:,:]
    hemL_towL_weights   = towL_weights[isL,:,:]
    hemL_towR_weights   = towR_weights[isL,:,:]
    contraDelta_weights = delta_weights[isL,:,:] # since \Delta = R - L, contra is always left hemisphere
    ipsiDelta_weights   = delta_weights[isR,:,:] # since \Delta = R - L, ipsi is always right hemisphere

    # initialize vars
    num_lags_tow   = np.sum(towL_idx)
    num_lags_delta = np.sum(delta_idx)
    dt             = glm['summ'].glmCfg.timeBins[1] - glm['summ'].glmCfg.timeBins[0]
    num_mice       = len(glm_summ['mice'])
    num_areas  = len(glm_areas)
    glm_summ['tower_taxis']          = np.arange(0,num_lags_tow*dt,dt)
    glm_summ['delta_taxis']          = np.arange(0,num_lags_delta*dt,dt)
    glm_summ['contraTow_weights']    = np.zeros((num_areas,num_lags_tow,num_mice))
    glm_summ['ipsiTow_weights']      = np.zeros((num_areas,num_lags_tow,num_mice))
    glm_summ['contraTow_peakTime']   = np.zeros((num_areas,num_mice))
    glm_summ['ipsiTow_peakTime']     = np.zeros((num_areas,num_mice))
    glm_summ['contraDelta_weights']  = np.zeros((num_areas,num_lags_delta,num_mice))
    glm_summ['ipsiDelta_weights']    = np.zeros((num_areas,num_lags_delta,num_mice))
    glm_summ['contraDelta_peakTime'] = np.zeros((num_areas,num_mice))
    glm_summ['ipsiDelta_peakTime']   = np.zeros((num_areas,num_mice))

    # baseline subtract, normalize, smooth, measure time of peak coefficient value
    for iArea, area in enumerate(glm_summ['areaList']):
        is_area = np.array(glm_areas) == area
        for iMouse in range(num_mice):
            thisw_hRtR = hemR_towR_weights[is_area,:,iMouse][0]
            thisw_hRtL = hemR_towL_weights[is_area,:,iMouse][0]
            thisw_hLtR = hemL_towR_weights[is_area,:,iMouse][0]
            thisw_hLtL = hemL_towL_weights[is_area,:,iMouse][0]

            this_contra = sp.ndimage.gaussian_filter1d((thisw_hLtR + thisw_hRtL)/2,smooth_w)
            this_ipsi   = sp.ndimage.gaussian_filter1d((thisw_hLtL + thisw_hRtR)/2,smooth_w)
            this_contra = this_contra - np.min(this_contra)
            this_contra = this_contra / np.max(this_contra)
            this_ipsi   = this_ipsi - np.min(this_ipsi)
            this_ipsi   = this_ipsi / np.max(this_ipsi)

            glm_summ['contraTow_weights'][iArea,:,iMouse] = this_contra
            glm_summ['contraTow_peakTime'][iArea,iMouse]  = glm_summ['tower_taxis'][this_contra==np.max(this_contra)]
            glm_summ['ipsiTow_weights'][iArea,:,iMouse] = this_ipsi
            glm_summ['ipsiTow_peakTime'][iArea,iMouse]  = glm_summ['tower_taxis'][this_ipsi==np.max(this_ipsi)]

            thisw = contraDelta_weights[is_area,:,iMouse][0]
            thisw = sp.ndimage.gaussian_filter1d(thisw,smooth_w)
            thisw = thisw - np.min(thisw)
            thisw = thisw / np.max(thisw)
            glm_summ['contraDelta_weights'][iArea,:,iMouse] = thisw
            glm_summ['contraDelta_peakTime'][iArea,iMouse]  = glm_summ['delta_taxis'][thisw==np.max(thisw)]

            thisw = ipsiDelta_weights[is_area,:,iMouse][0]
            thisw = sp.ndimage.gaussian_filter1d(thisw,smooth_w)
            thisw = thisw - np.min(thisw)
            thisw = thisw / np.max(thisw)

            glm_summ['ipsiDelta_weights'][iArea,:,iMouse] = thisw
            glm_summ['ipsiDelta_peakTime'][iArea,iMouse]  = glm_summ['delta_taxis'][thisw==np.max(thisw)]

    # one-way ANOVA with RM for peaks
    table = pd.DataFrame({'area' : np.repeat(range(num_areas), num_mice),
                          'mouse': np.tile(range(num_mice), num_areas),
                          'contraTow_peakTime' : glm_summ['contraTow_peakTime'].flatten()})
    glm_summ['contraTow_peakTime_anova_table'] = pg.rm_anova(dv='contraTow_peakTime', within='area',subject='mouse',data=table)
    glm_summ['contraTow_peakTime_anova_pval']  = glm_summ['contraTow_peakTime_anova_table']['p-unc'].to_numpy()

    table = pd.DataFrame({'area' : np.repeat(range(num_areas), num_mice),
                          'mouse': np.tile(range(num_mice), num_areas),
                          'ipsiTow_peakTime' : glm_summ['ipsiTow_peakTime'].flatten()})
    glm_summ['ipsiTow_peakTime_anova_table'] = pg.rm_anova(dv='ipsiTow_peakTime', within='area',subject='mouse',data=table)
    glm_summ['ipsiTow_peakTime_anova_pval']  = glm_summ['ipsiTow_peakTime_anova_table']['p-unc'].to_numpy()

    table = pd.DataFrame({'area' : np.repeat(range(num_areas), num_mice),
                          'mouse': np.tile(range(num_mice), num_areas),
                          'contraDelta_peakTime' : glm_summ['contraDelta_peakTime'].flatten()})
    glm_summ['contraDelta_peakTime_anova_table'] = pg.rm_anova(dv='contraDelta_peakTime', within='area',subject='mouse',data=table)
    glm_summ['contraDelta_peakTime_anova_pval']  = glm_summ['contraDelta_peakTime_anova_table']['p-unc'].to_numpy()

    table = pd.DataFrame({'area' : np.repeat(range(num_areas), num_mice),
                          'mouse': np.tile(range(num_mice), num_areas),
                          'ipsiDelta_peakTime' : glm_summ['ipsiDelta_peakTime'].flatten()})
    glm_summ['ipsiDelta_peakTime_anova_table'] = pg.rm_anova(dv='ipsiDelta_peakTime', within='area',subject='mouse',data=table)
    glm_summ['ipsiDelta_peakTime_anova_pval']  = glm_summ['ipsiDelta_peakTime_anova_table']['p-unc'].to_numpy()

    return glm_summ

# ==============================================================================
# plot model coefficients related to towers
def plot_tower_weights(glm_summ,plot_median=True):

    """
    fig = plot_tower_weights(glm_summ,plot_median=True)
    plots contralateral and \delta tower weights and analysis thereof for each area
    glm_summ is output of summarize_glm, fig is fig handle
    plot_median is boolean to show median rather than mean across mice
    """

    fig    = plt.figure(figsize=(5,6.5))
    cl     = utils.getAreaColors(glm_summ['areaList'])
    nareas = len(glm_summ['areaList'])
    nmice  = np.size(glm_summ['contraTow_peakTime'],axis=1)

    # plot contralateral tower weights by time
    plot_what = 'contraTow_weights'
    taxis     = glm_summ['tower_taxis']
    for iArea in range(nareas):
       ax    = fig.add_subplot(4,4,iArea+1)
       thism = np.mean(glm_summ[plot_what][iArea,:,:],axis=1)
       thiss = np.std(glm_summ[plot_what][iArea,:,:],axis=1,ddof=1) / np.sqrt(nmice-1)
       ax.fill_between(taxis,thism-thiss,thism+thiss,color=[.7,.7,.7,.5])
       ax.plot(taxis,thism,color=cl[iArea],lw=1.5)

       ax.set_xticks(np.arange(0,2.5,.5))
       ax.set_yticks(np.arange(0,1.25,.25))
       ax.set_xlim([0,2])
       ax.set_ylim([0,1])

       if iArea == 4:
           ax.set_xlabel('Lag (s)')
           ax.set_ylabel('Norm. contra tower coeff.')
       ax = utils.applyPlotDefaults(ax)

    # plot peaks per area / mouse
    ax = fig.add_subplot(4,4,8)
    plot_what = 'contraTow_peakTime'
    jitter    = np.random.uniform(size=(nmice))*0.05-0.025
    for iArea in range(nareas):
       this_peak = glm_summ[plot_what][iArea,:]
       ax.bar(iArea,np.mean(this_peak),color=cl[iArea])
       ax.errorbar(iArea,np.mean(this_peak),np.std(this_peak,ddof=1)/np.sqrt(nmice-1),color=cl[iArea])
       ax.plot(iArea+jitter,this_peak,marker='.',c=[.6,.6,.6,.5], ls='None')

    ax.set_xticks(np.arange(nareas))
    ax.set_xticklabels(glm_summ['areaList'],rotation=90)
    ax.set_yticks(np.arange(0,2.5,.5))
    ax.set_xlim([-.5,iArea+.5])
    ax.set_ylim([0,2.05])
    ax.set_ylabel('Time of peak (s)')
    # print ANOVA p (bins)
    plt.text(0,2.2,'p = {:.2f}'.format(glm_summ['contraTow_peakTime_anova_pval'][0]),fontsize=8,color='k')

    ax = utils.applyPlotDefaults(ax)

    # plot contralateral \Delta tower weights by time
    plot_what = 'contraDelta_weights'
    taxis     = glm_summ['delta_taxis']
    for iArea in range(nareas):
       ax    = fig.add_subplot(4,4,iArea+2+nareas)
       thism = np.mean(glm_summ[plot_what][iArea,:,:],axis=1)
       thiss = np.std(glm_summ[plot_what][iArea,:,:],axis=1,ddof=1) / np.sqrt(nmice-1)
       ax.fill_between(taxis,thism-thiss,thism+thiss,color=[.7,.7,.7,.5])
       ax.plot(taxis,thism,color=cl[iArea],lw=1.5)

       ax.set_xticks(np.arange(0,2.5,.5))
       ax.set_yticks(np.arange(0,1.25,.25))
       ax.set_xlim([0,2])
       ax.set_ylim([0,1])

       if iArea == 4:
           ax.set_xlabel('Lag (s)')
           ax.set_ylabel('Norm. \u0394 towers coeff.')
       ax = utils.applyPlotDefaults(ax)

    # plot peaks per area / mouse
    ax = fig.add_subplot(4,4,16)
    plot_what = 'contraDelta_peakTime'
    jitter    = np.random.uniform(size=(nmice))*0.05-0.025
    for iArea in range(nareas):
       this_peak = glm_summ[plot_what][iArea,:]
       if plot_median:
           thism = np.median(this_peak)
           thiss = sp.stats.iqr(this_peak)
       else:
           thism = np.mean(this_peak)
           thiss = np.std(this_peak,ddof=1)/np.sqrt(nmice-1)
       ax.bar(iArea,thism,color=cl[iArea])
       ax.errorbar(iArea,thism,thiss,color=cl[iArea])
       ax.plot(iArea+jitter,this_peak,marker='.',c=[.6,.6,.6,.5], ls='None')

    ax.set_xticks(np.arange(nareas))
    ax.set_xticklabels(glm_summ['areaList'],rotation=90)
    ax.set_yticks(np.arange(0,2.5,.5))
    ax.set_xlim([-.5,iArea+.5])
    ax.set_ylim([0,2.05])
    ax.set_ylabel('Time of peak (s)')
    # print ANOVA p (bins)
    plt.text(0,2.2,'p = {:.2f}'.format(glm_summ['contraDelta_peakTime_anova_pval'][0]),fontsize=8,color='k')
    ax = utils.applyPlotDefaults(ax)

    fig.subplots_adjust(left=.1, bottom=.25, right=.95, top=.75, wspace=.75, hspace=.75)

    return fig

# ==============================================================================
# plot glm timescales
def plot_glm_timescales(glm_summ,glm,plot_median=True,wf_params=wf_params):

    """
    fig, figdata = plot_glm_timescales(glm_summ,glm,plot_median=True)
    takes glm and glm_summ dictionaries, plots data summary and examples with emphasis on timescales
    plot_median is boolean to show median rather than mean across mice
    returns figure handle fig and source data dictionary figdata
    """

    colors    = utils.getAreaColors(glm_summ['areaList'])
    num_areas = len(glm_summ['areaList'])
    fig       = plt.figure(figsize=(5,4.5))
    figdata   = dict()

    # plot model performance
    ax  = fig.add_subplot(2,4,5)
    acc = glm_summ['accuracy_mice'][:,:,-1].flatten()
    ax.hist(acc,bins=np.arange(0,1.05,.05),color=[.5,.5,.5])
    ax.set_xticks(np.arange(0,1.25,.25))
    ax.set_xlabel('Cross-val. accuracy (avg. r)')
    ax.set_ylabel('Num. observations\n(Mice * ROI)')
    ax = utils.applyPlotDefaults(ax)
    figdata['glm_xval_accuracy_corrcoeff'] = acc

    # plot example model predictions
    area_eg_idx  = wf_params['area_eg_idx_glm']
    data_points  = wf_params['trial_idx_glm']
    xaxis        = np.arange(0,len(data_points)*.1,.1)
    subplot      = [2, 6, 10, 14]

    figdata['glm_examples_xaxis']       = xaxis
    figdata['glm_examples_xaxis_label'] = 'Time from trial start (s)'
    figdata['glm_examples_yaxis_label'] = '\DeltaF/F (z-score)'
    figdata['glm_examples_areaLabels']  = list()
    figdata['glm_examples_data']        = list()
    figdata['glm_examples_prediction']  = list()
    for iEg in range(len(area_eg_idx)):
        ax = fig.add_subplot(4,4,subplot[iEg])
        if iEg == len(area_eg_idx):
            data_points = data_points + 38 # hack: M1 is misaligned due to some NaN in this file
        thisy = sp.ndimage.gaussian_filter1d(glm['eg']['y'][area_eg_idx[iEg]][data_points], 1)
        figdata['glm_examples_data'].append(thisy)
        ax.plot(xaxis,thisy,linestyle='-',linewidth=.75,color=[.3, .3, .3],label='Data')
        thisy = sp.ndimage.gaussian_filter1d(glm['eg']['yhat'][area_eg_idx[iEg]][data_points], 1)
        figdata['glm_examples_prediction'].append(thisy)
        thiscl = utils.getAreaColors([glm['eg']['ROIlbl'][area_eg_idx[iEg]]])
        ax.plot(xaxis,thisy,linestyle='-',linewidth=1,color=thiscl[0],label='Prediction')
        ax.set_xticks(range(0,6,1))
        ax.set_title(glm['eg']['ROIlbl'][area_eg_idx[iEg]])

        if iEg == 2:
            ax.set_xlabel('Time from trial start (s)')
        if iEg == 3:
            ax.set_ylabel('Df/f (z-score)')

        utils.applyPlotDefaults(ax)
        figdata['glm_examples_areaLabels'].append(glm['eg']['ROIlbl'][area_eg_idx[iEg]])

    # plot example exponential fits
    # subplot      = [4, 5, 11, 12]
    subplot      = [3, 7, 11, 15]
    area_eg_idx  = wf_params['area_eg_idx_autoregr']
    figdata['expfit_examples_xaxis']       = -(np.flip(glm_summ['acorr_lags']+.1))
    figdata['expfit_examples_xaxis_label'] = 'Lag (s)'
    figdata['expfit_examples_yaxis_label'] = 'Norm. auto-regr. coeff.'
    figdata['expfit_examples_areaLabels']  = list()
    figdata['expfit_examples_data']        = list()
    figdata['expfit_examples_prediction']  = list()
    for iEg in range(len(area_eg_idx)):
        ax      = fig.add_subplot(4,4,subplot[iEg])
        areaidx = area_eg_idx[iEg]
        thisy   = glm_summ['acorr_weights'][areaidx,:,wf_params['mouse_eg_id']]
        ax.plot(-(np.flip(glm_summ['acorr_lags']+.1)),np.flip(thisy),linestyle='-',linewidth=.75,color=[.3, .3, .3],label='Data')
        figdata['expfit_examples_data'].append(np.flip(thisy))

        thisy   = glm_summ['acorr_fit_mice'][areaidx,:,wf_params['mouse_eg_id']]
        thiscl  = utils.getAreaColors([glm_summ['areaList'][areaidx]])
        ax.plot(-(np.flip(glm_summ['acorr_xaxis']+.1)),np.flip(thisy),linestyle='-',linewidth=1,color=thiscl[0],label='Prediction')
        ax.set_xticks(np.arange(-1,.25,.25))
        ax.set_xlim([-1,0])
        ax.set_title(glm_summ['areaList'][areaidx])

        figdata['expfit_examples_prediction'].append(np.flip(thisy))
        figdata['expfit_examples_areaLabels'].append(glm_summ['areaList'][areaidx])

        # if iEg == 0:
        # ax.legend()
        if iEg == 2:
            ax.set_xlabel('Lag (s)')
        if iEg == 3:
            ax.set_ylabel('Norm. auto-regr. coeff.')

        utils.applyPlotDefaults(ax)

    # plot exp. model R2
    ax  = fig.add_subplot(3,4,4)
    acc = glm_summ['acorr_fit_r2'].flatten()
    ax.hist(acc,bins=np.arange(0,1.05,.05),color=[.5,.5,.5])
    ax.set_xticks(np.arange(0,1.25,.25))
    ax.set_xlabel('Exponential fit R^2')
    ax.set_ylabel('Num. observations\n(Mice * ROI)')
    ax = utils.applyPlotDefaults(ax)
    figdata['exponentialFit_r2'] = acc

    # plot average fits
    ax = fig.add_subplot(3,4,8)
    figdata['expfit_areaList'] = glm_summ['areaList']
    figdata['expFit_area_avg'] = list()
    for iArea in range(num_areas):
        plt.plot(-(np.flip(glm_summ['acorr_xaxis']+.1)),np.flip(glm_summ['acorr_fit_pred'][iArea,:]),color=colors[iArea],linewidth=.5)
        figdata['expFit_area_avg'].append(np.flip(glm_summ['acorr_fit_pred'][iArea,:]))
    ax.set_xlabel('Lag (s)')
    ax.set_ylabel('Norm. auto-regr. coeff.')
    ax.set_xticks(np.arange(-.5,.1,.1))
    ax.set_yticks(np.arange(0,1.25,.25))
    ax.set_xlim([-.5,-.05])
    ax.set_ylim([0,1])
    ax = utils.applyPlotDefaults(ax)

    # plot taus
    figdata['expFit_tau_bymouse'] = list()
    if plot_median:
        figdata['expFit_tau_median']      = list()
        figdata['expFit_tau_interQrange'] = list()
    else:
        figdata['expFit_tau_mean']        = list()
        figdata['expFit_tau_sem']         = list()

    num_mice = np.size(glm_summ['taus'],axis=1)
    jitter   = np.random.uniform(size=(num_mice))*0.1-0.05
    ax       = fig.add_subplot(3,4,12)
    for iArea in range(num_areas):
        taus     = glm_summ['taus'][iArea,:]
        figdata['expFit_tau_bymouse'].append(taus)
        if plot_median:
            thismean = np.median(taus)
            thissem = sp.stats.iqr(taus)
            figdata['expFit_tau_median'].append(thismean)
            figdata['expFit_tau_interQrange'].append(thissem)
        else:
            thismean = np.mean(taus)
            thissem  = np.std(taus,ddof=1)/np.sqrt(num_mice)
            figdata['expFit_tau_mean'].append(thismean)
            figdata['expFit_tau_sem'].append(thissem)

        plt.bar(iArea,thismean,facecolor=colors[iArea])
        plt.errorbar(iArea,thismean,thissem,color=colors[iArea])
        ax.plot(iArea+jitter,taus,marker='.',c=[.6,.6,.6,.5], ls='None')

    ax.set_xticks(range(num_areas))
    ax.set_xticklabels(glm_summ['areaList'],rotation=90)
    ax.set_ylabel('$\u03C4$ (s)')
    ax.set_ylim([0, .4])
    ax.set_yticks(np.arange(0,.45,.1))
    ax.text(0,.15,'p = {:1.3f}'.format(glm_summ['taus_anova_pval'][0]))
    ax = utils.applyPlotDefaults(ax)
    figdata['expFit_tau_pval']  = glm_summ['taus_anova_pval'][0]

    fig.subplots_adjust(left=.1, bottom=.25, right=.95, top=.75, wspace=.75, hspace=1)

    return fig, figdata

# ==============================================================================
# plot glm timescales
def plot_glm_timescales_space(glm_summ,glm):

    """
    fig = plot_glm_timescales(glm_summ,glm)
    takes glm and glm_summ dictionaries, plots data summary and examples with emphasis on timescales
    returns figure handle fig
    """

    colors = utils.getAreaColors(glm_summ['areaList'])
    num_areas = len(glm_summ['areaList'])
    fig = plt.figure(figsize=(5,4))

    # plot model performance
    ax = fig.add_subplot(2,4,5)
    for iArea in range(num_areas):
        plt.plot(glm_summ['accuracy_mean'][iArea,:],color=colors[iArea])
    ax.set_xticks(range(4))
    ax.set_xticklabels(glm_summ['model_names'],rotation=90)
    ax.set_ylabel('Cross-val accuracy (r)')
    ax.legend(glm_summ['areaList'],fontsize='x-small',ncol=1)
    ax.set_xlim([-.25,3.25])
    ax = utils.applyPlotDefaults(ax)

    # plot example model predictions
    area_eg_idx  = wf_params['area_eg_idx_glm']
    data_points  = range(wf_params['trial_idx_glm']*60,(wf_params['trial_idx_glm']+1)*60)
    xaxis        = np.arange(0,300,5)
    # subplot      = [2, 3, 9, 10]
    subplot      = [2, 6, 10, 14]

    for iEg in range(len(area_eg_idx)):
        ax = fig.add_subplot(4,4,subplot[iEg])
        thisy = sp.ndimage.gaussian_filter1d(glm['eg']['y'][area_eg_idx[iEg]][data_points], 1)
        ax.plot(xaxis,thisy,linestyle='-',linewidth=.75,color=[.3, .3, .3],label='Data')
        thisy = sp.ndimage.gaussian_filter1d(glm['eg']['yhat'][area_eg_idx[iEg]][data_points], 1)
        thiscl = utils.getAreaColors([glm['eg']['ROIlbl'][area_eg_idx[iEg]]])
        ax.plot(xaxis,thisy,linestyle='-',linewidth=1,color=thiscl[0],label='Prediction')
        ax.set_xticks(range(0,400,100))
        ax.set_title(glm['eg']['ROIlbl'][area_eg_idx[iEg]])

        if iEg == 2:
            ax.set_xlabel('y pos. (cm)')
        if iEg == 3:
            ax.set_ylabel('Df/f (z-score)')

        utils.applyPlotDefaults(ax)

    # plot example exponential fits
    # subplot      = [4, 5, 11, 12]
    subplot      = [3, 7, 11, 15]
    area_eg_idx  = wf_params['area_eg_idx_autoregr']
    for iEg in range(len(area_eg_idx)):
        ax      = fig.add_subplot(4,4,subplot[iEg])
        areaidx = area_eg_idx[iEg]
        thisy   = glm_summ['acorr_weights'][areaidx,:,wf_params['mouse_eg_id']]
        ax.plot(glm_summ['acorr_lags']+5,thisy,linestyle='-',linewidth=.75,color=[.3, .3, .3],label='Data')

        thisy   = glm_summ['acorr_fit_mice'][areaidx,:,wf_params['mouse_eg_id']]
        thiscl  = utils.getAreaColors([glm_summ['areaList'][areaidx]])
        ax.plot(glm_summ['acorr_xaxis']+5,thisy,linestyle='-',linewidth=1,color=thiscl[0],label='Prediction')
        ax.set_xticks(range(0,125,25))
        ax.set_xlim([0,50])
        ax.set_title(glm_summ['areaList'][areaidx])

        # if iEg == 0:
        # ax.legend()
        if iEg == 2:
            ax.set_xlabel('Lag (cm)')
        if iEg == 3:
            ax.set_ylabel('Norm. auto-regr. coeff.')

        utils.applyPlotDefaults(ax)

    # plot average fits
    ax = fig.add_subplot(2,4,4)
    for iArea in range(num_areas):
        plt.plot(glm_summ['acorr_xaxis']+5,glm_summ['acorr_fit_pred'][iArea,:],color=colors[iArea],linewidth=.5)
    ax.set_xlabel('Lag (cm)')
    ax.set_ylabel('Norm. auto-regr. coeff.')
    ax.set_xlim([2,25])
    ax.set_xticks(range(5,30,10))
    ax = utils.applyPlotDefaults(ax)

    # plot taus
    num_mice = np.size(glm_summ['taus'],axis=1)
    ax = fig.add_subplot(2,4,8)
    for iArea in range(num_areas):
        thismean = np.mean(glm_summ['taus'][iArea,:])
        thissem  = np.std(glm_summ['taus'][iArea,:],ddof=1)/np.sqrt(num_mice)
        plt.bar(iArea,thismean,facecolor=colors[iArea])
        plt.errorbar(iArea,thismean,thissem,color=colors[iArea])
    ax.set_xticks(range(num_areas))
    ax.set_xticklabels(glm_summ['areaList'],rotation=90)
    ax.set_ylabel('$\u03C4$ (cm)')
    ax.set_ylim([0, 4])
    ax.text(0,3,'p = {:1.3f}'.format(glm_summ['taus_anova_pval'][0]))
    ax = utils.applyPlotDefaults(ax)

    fig.subplots_adjust(left=.1, bottom=.25, right=.95, top=.75, wspace=.75, hspace=1)

    return fig

# ==============================================================================
# exponential decay function for fits
def exp_decay(x,tau,a,b):
    return b+a*np.exp(-x/tau)

# ==============================================================================
# plot ROI activity predictors
def plot_corr_pred(glm):

    """
    fig = plot_corr_pred(glm)
    takes glm dictionary, plots coupling coefficients
    returns figure handle fig
    """

    # extract relevant predictors
    ispred_idx  = np.array([glm['summ'].predLbls[iPred].find('ROI') \
                           for iPred in range(np.size(glm['summ'].predLbls))])==0
    num_areas   = np.size(glm['summ'].ROIlbl)
    num_mice    = np.size(glm['summ'].weights,axis=2)
    weights     = np.ones((num_areas,num_areas,num_mice)) * np.nan

    # there are no self predictors, fill in accordingly
    for iArea in range(num_areas):
        area_idx                  = np.zeros(num_areas) == 0
        area_idx[iArea]           = False
        weights[iArea,area_idx,:] = glm['summ'].weights[iArea,ispred_idx,:]

    weights  = weights[:-2,:-2,:] # remove somatosensory ctx from analysis
    wmean    = np.mean(weights,axis=2) # avg across mice

    # plot
    fig = plt.figure(figsize=(3,3))
    ax  = fig.gca()
    plt.imshow(wmean,vmin=-0.3,vmax=0.3,cmap='PuOr')
    cb  = plt.colorbar(ax=ax)
    cb.set_label('ROI activity coefficient')
    ax.set_xticks(range(num_areas-2))
    ax.set_xticklabels(glm['summ'].ROIlbl[:-2],rotation=90)
    ax.set_yticks(range(num_areas-2))
    ax.set_yticklabels(glm['summ'].ROIlbl[:-2])

    return fig


class Solution:
    def isBipartite(self, graph: List[List[int]]) -> bool:
        self.graph = graph
        # Graph Coloring
        self.color = {}
        for index in range(len(graph)):
            if index not in self.color:
                # Initial Color of node is 0
                self.color[index] = 0
                # Call for DFS Traversal of this node
                if not self.dfs(index):
                    return False
        return True

    def dfs(self, index):
        # Traverse Adjacent Nodes
        for adj in self.graph[index]:
            # If Adjacent node is not colored yet, color it
            if adj not in self.color:
                self.color[adj] = 1 - self.color[index]
                # Call for this adjacent node DFS
                if not self.dfs(adj):
                    return False
            else:
                # If adjacent node is colored and having same color as node on other edge then
                # it means they are in same setso return False
                if self.color[adj] == self.color[index]:
                    return False
        return True


# -*- coding: utf-8 -*-
"""
Created on Tue Dec 22 05:41:38 2020

@author: Marysia
Puzzle 22 part 1 from https://adventofcode.com/2020/day/22
--- Day 22: Crab Combat ---

Before the game starts, split the cards so each player has their own deck (your
puzzle input). Then, the game consists of a series of rounds: both players draw
their top card, and the player with the higher-valued card wins the round. The
winner keeps both cards, placing them on the bottom of their own deck so that
the winner's card is above the other card. If this causes a player to have all
of the cards, they win, and the game ends.

Once the game ends, you can calculate the winning player's score. The bottom card
in their deck is worth the value of the card multiplied by 1, the
second-from-the-bottom card is worth the value of the card multiplied by 2, and so on.

Play the small crab in a game of Combat using the two decks you just dealt.
What is the winning player's score?
"""

def get_data():
    with open('input.txt', 'r') as in_file:
        data_str = in_file.read()
    return data_str.split('\n')

def play_game(p1, p2):
    while bool(p1) and bool(p2):
        card1 = p1.pop(0)
        card2 = p2.pop(0)
        if card1 > card2:
            p1 += [card1, card2]
        else:
            p2 += [card2, card1]
    return p1, p2

def determine_score(p1, p2):
    if p1 > p2:
        score = 0
        for i, card in enumerate(p1):
            score += card * (len(p1)-i)
    else:
        score = 0
        for i, card in enumerate(p2):
            score += card * (len(p2)-i)
    return score

INPUT = get_data()
PLAYER1, PLAYER2 = play_game([int(_) for _ in INPUT[1:INPUT.index('')]],
                             [int(_) for _ in INPUT[INPUT.index('')+2:]])
print(determine_score(PLAYER1, PLAYER2))


import argparse
import re
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
def file_scan(pos_file,neg_file):
    #words_df = pd.DataFrame(columns=['Positive','Negative'])
    words = {}
    lines = open(pos_file, encoding='utf8').read().splitlines()
    #lines = open("hotelPosT-train.txt",encoding='utf8').read().splitlines()
    for line in lines:
        line = re.sub('ID-[0-9][0-9][0-9][0-9]\s','',line)
        list_line = re.findall("(?<!\S)[A-Za-z]+(?!\S)|(?<!\S)[A-Za-z]+(?=:(?!\S))", line)
        filtered_line = [word for word in list_line if word not in stopwords.words('english')]
        filtered_line = [x.lower() for x in filtered_line]
        for word in filtered_line:
            if word in words:
                words[word][0] += 1
            else:
                words[word] = [2,1]

    lines = open(neg_file, encoding='utf8').read().splitlines()
    #lines = open("hotelNegT-train.txt", encoding='utf8').read().splitlines()
    for line in lines:
        line = re.sub('ID-[0-9][0-9][0-9][0-9]\s', '', line)
        list_line = re.findall("(?<!\S)[A-Za-z]+(?!\S)|(?<!\S)[A-Za-z]+(?=:(?!\S))", line)
        filtered_line = [word for word in list_line if word not in stopwords.words('english')]
        filtered_line = [x.lower() for x in filtered_line]
        for word in filtered_line:
            if word in words:
                words[word][1] += 1
            else:
                words[word] = [1, 2]

    return words

def naive_bayes(words,test_file):
    lines = open(test_file, encoding='utf8').read().splitlines()
    #lines = open("finalTest.txt", encoding='utf8').read().splitlines()
    answrite = open("answer.txt",'w',encoding='utf8')
    line_count = 0
    pos_count = 0
    neg_count = 0
    stopWord = set(stopwords.words('english'))
    stopWord.update(
        ['','internet','high', 'speed', 'thing', '--', 'place', 'thought', 'paid', 'overall', 'i\'m', 'i\'ll', 'house', 'carrying',
         'around', 'many', 'staying', 'stayed', 'enjoy', 'without', 'partying', 'sitting', 'coming', 'provided',
          'entered', 'events', 'going', 'city', 'life', 'sheraton',  'strip','location',  'questions', 'passed', 'food', 'store', 'actually', 'fan', 'tv',
         'pool', 'paint', 'walls', 'restaurant', 'downstairs','cigarette', 'indoor','street', 'union', 'entire', 'hear', 'wifi','much', 'came', 'late', 'last', 'spot', 'buses', 'ran', 'checked', 'checking',
         'clerk', 'two', '&', 'found', 'king', 'suite', 'called', 'motel', 'back', 'front', 'rooms',
         'breakfast', 'continental', 'area', 'staff', 'located', 'though',  'first', 'ac','us', 'casino', 'starter', 'get', 'hotels', 'movie', 'room'])
    stop_list = list(stopWord)
    for line in lines:
        line_count += 1
        id_no = re.match('ID-[0-9][0-9][0-9][0-9]\s', line)
        line = re.sub('ID-[0-9][0-9][0-9][0-9]\s', '', line)
        list_line = re.findall("(?<!\S)[A-Za-z]+(?!\S)|(?<!\S)[A-Za-z]+(?=:(?!\S))", line)
        filtered_line = [word for word in list_line if word not in stop_list]
        filtered_line = [x.lower() for x in filtered_line]
        pos = 1
        neg = 1
        for word in filtered_line:
            if word in words:
                pos = pos * words[word][0]
                neg = neg * words[word][1]
        if pos >= neg:
            pos_count += 1
            answrite.write(id_no.group(0) + ' POS')
        else:
            neg_count += 1
            answrite.write(id_no.group(0) + ' NEG')
        answrite.write("\n")

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("pos_file")
    parser.add_argument("neg_file")
    parser.add_argument("testfile")
    args = parser.parse_args()
    pos_file = args.pos_file
    neg_file = args.neg_file
    test_file = args.testfile
    words_dict = file_scan(pos_file,neg_file)
    naive_bayes(words_dict,test_file)
if __name__ == '__main__':
    main()


import sys

class Bank:
    bankName = "Nabil Bank"

    def __init__(self,name,balance=0.0):
        self.name = name
        self.balance = balance

    def deposit(self, dAmount):
        self.balance = self.balance + dAmount
        print("The balance after deposit : ", self.balance)

    def withdraw(self, wAmount):
        if wAmount > self.balance:
            print("Insufficient Funds ... Cannot perform this operation")
            sys.exit()
        self.balance = self.balance - wAmount
        print("Balance after withdraw : ", self.balance)

print("Welcome to ", Bank.bankName)
name = input("Enter Your name : ")

bank = Bank(name)
while True:
    print("d for Deposit \nw for withdraw \nc for Check Balance \ne for Exit")
    option = input("Enter Your Option : ")
    if option.lower() == "d":
        amount = eval(input("Enter Amount tp deposit : "))
        bank.deposit(amount)
    elif option.lower() == "w":
        amount = eval(input("Enter Amount tp withdraw : "))
        bank.withdraw(amount)
    elif option.lower() == "c":
        print("Your Balance is ", bank.balance)
    elif option.lower() == "e":
        print("Thanks for banking with" , bank.bankName)
        sys.exit()
    else:
        print("invalid Option please choose correct option")