# -*- coding: utf-8 -*-
"""
Created on Mon Feb 28 2020

@author: Pierre-Marie EDLINGER
"""
import cv2
import RutaipCommonFunctions as Rtp
from datetime import datetime

testMenton=False
testProfilGauche=False
testProfilDroit=False
visageFaceDecele=False
profileDecele=False
retourFace=False
testMentonCommence = False
testProfGaucheCommence = False
testProfDroitCommence = False

#création d'un répertoire + nommage du fichier final
Rtp.creationRepertoireImage()
cheminImage = './Images/images_TestYeux.jpg'

#Ouverture de la camera
cap = Rtp.choixCamera()
#cap = cv2.VideoCapture(0)

# initialize the recognizers
face_cascade=cv2.CascadeClassifier("./Haarcascade/haarcascade_frontalface_alt2.xml")
profile_cascade=cv2.CascadeClassifier("./Haarcascade/haarcascade_profileface.xml")

now = datetime.now()

"""
trouver le visage de face
lui demander de baisser le menton --> le visage ne doit plus être décelé
merci, regardez en face de vous
lui demander de tourner la tête à droite --> le profil gauche doit être décelé
merci, regardez en face de vous
lui demander de tourner la tête à gauche --> un profil droit doit être décelé
merci, cet exercice a-t-il été douloureux pour vous?
Proposer fenêtre de réponse
donner résultat

"""

while True:

    later = datetime.now()
    difference = (later - now).total_seconds()

    # read the image from the cam
    ret, frame = cap.read()

    # converting to grayscale
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # detect all the faces in the image
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)

    # detect all the profiles in the image
    profiles = profile_cascade.detectMultiScale(gray, 1.2, 5)

    #Rtp.joueSon("./Sons/OpenEyes.mp3")

    # for every face, draw a blue rectangle
# =============================================================================
#     for x, y, width, height in faces:
#         cv2.rectangle(frame, (x, y), (x + width, y + height), color=(255, 0, 0), thickness=2)
# =============================================================================

    if len(faces)>0:
        visageFaceDecele=True
    else:
        visageFaceDecele=False

    # for every profile, draw a green rectangle
# =============================================================================
#     for x1, y1, width1, height1 in profiles:
#         cv2.rectangle(frame, (x1, y1), (x1 + width1, y1 + height1), color=(0, 255, 0), thickness=2)
# =============================================================================

    if len(profiles)>0:
        profileDecele=True
    else:
        profileDecele=False

# """
# trouver le visage de face
# lui demander de baisser le menton --> le visage ne doit plus être décelé
# merci, regardez en face de vous
# lui demander de tourner la tête à droite --> le profil gauche doit être décelé
# merci, regardez en face de vous
# lui demander de tourner la tête à gauche --> un profil droit doit être décelé
# merci, cet exercice a-t-il été douloureux pour vous?
# Proposer fenêtre de réponse
# donner résultat

# """

    if (testMenton==False):
        if testMentonCommence==False:
            print("test menton")
            Rtp.joueSon("./Sons/BaisserMenton.mp3")
            testMentonCommence=True

        if visageFaceDecele==False:
            print("test menton fait")
            Rtp.joueSon("./Sons/LookForward.mp3")
            testMenton=True
            now = datetime.now()

    else : # le test du menton a été fait, on passe aux tests suivants
        if (testProfilGauche==False):
            later = datetime.now()
            difference = (later - now).total_seconds()

            if difference >=4 :
                if testProfGaucheCommence == False:
                    print("test profile gauche")
                    Rtp.joueSon("./Sons/TeteADroite.mp3")
                    testProfGaucheCommence=True

            if (profileDecele==True)&(visageFaceDecele==False):
                print("test profil gauche fait")
                testProfilGauche=True
                retourFace=False
                now = datetime.now()
                Rtp.joueSon("./Sons/LookForward.mp3")

        else : # le test du profil gauche a été fait, on passe au profil droit
            if (testProfilDroit==False):
                later = datetime.now()
                difference = (later - now).total_seconds()

                if difference >=4 :
                    if testProfDroitCommence == False:
                        print("test profile droit")
                        Rtp.joueSon("./Sons/TeteAGauche.mp3")
                        testProfDroitCommence=True

                    if (profileDecele==True)&(visageFaceDecele==False)&(retourFace==True):
                        print("test profil droit fait")
                        testProfilDroit=True

    if (testMenton)&(testProfilGauche)&(visageFaceDecele):
        retourFace = True

    if (testMenton)&(testProfilGauche)&(testProfilDroit):
        #print("Demander si douleur")
        Rtp.joueSon("./Sons/Douloureux.mp3")
        #Rtp.dormir(1)
        if Rtp.poseQuestion("Questionnaire", "Ce test a-t-il été douloureux pour vous?"):
            print("Douloureux")
        else:
            print("Pas douloureux")
        break

    cv2.imshow("image", frame)

    #On quitte lorsque la touche "q" est pressée
    if cv2.waitKey(1) == ord("q"):
        break

cap.release()
cv2.destroyAllWindows()


"""
consider we have a simple term system with arithmetic operators ....

    1 + 2, 1 - 3, 2 + (3 - 1)

and a set of corresponding data structures

"""

import abc

class Term(abc.ABC):
    def __init__(self):
        self.comment = None

class Value(Term):
    def __init__(self, val):
        Term.__init__(self)

        assert isinstance(val, int)
        self.val = val

class BinaryOperation(Term):
    def __init__(self, opr, left, right):
        Term.__init__(self)

        assert opr in ['+', '-', '*']
        self.opr = opr
        assert isinstance(left, Term)
        self.left = left
        assert isinstance(right, Term)
        self.right = right

# Question 0
# read and try to understand why the following function works

def return_type_check(type):
    # this function returns another function that works as a decorator
    def checker(f):

        def g(*args, **kwargs):
            result = f(*args, **kwargs)
            assert isinstance(result, type), "type checking failed!"
            return result

        return g

    return checker

# Question 1
# write a function that parses a dictionary to a term

@return_type_check(Term)
def parse(raw_item):
    if raw_item['type'] == 'value':
        return Value(raw_item['val'])
    elif raw_item['type'] == 'binaryoperator':
        # TODO fill your code here
        pass

# test cases
# 5
parse({'type': 'value', 'val': 5})

# 5 + 5
parse({
    'type' : 'binaryoperation',
    'opr'  : '+',
    'left' : {'type': 'value', 'val': 5},
    'right': {'type': 'value', 'val': 5},
    })

# 5 - (2 * 3)
parse({
    'type' : 'binaryoperation',
    'opr'  : '-',
    'left' : {'type': 'value', 'val': 5},
    'right': {
        'type' : 'binaryoperation',
        'opr'  : '*',
        'left' : {'type': 'value', 'val': 2},
        'right': {'type': 'value', 'val': 3},
        },
    })

# Question 2
# write a enhanced function that parses a dictionary to a term,
# but this time there may be comments in dictionaries
#
# consider using decorators directly on the first `parse` function
# hint: search `Python 装饰器` on baidu.com

def add_comment(f):
    # TODO add your code here
    pass

def parse_with_comment(raw_item):
    @add_comment
    def _parse(raw_item):
        return parse(raw_item)

    return _parse(raw_item)

parse_with_comment({
    'type' : 'binaryoperator',
    'opr'  : '+',
    'left' : {'type': 'value', 'val': 5},
    'right': {'type': 'value', 'val': 5, 'comment': 'five'},
    'comment': 'this is an operator'
    })

# Question 3
# write a function that evaluates a term to a integer
def evaluate(t):
    assert isinstance(t, Term)
    pass

assert evaluate(parse({
    'type' : 'binaryoperation',
    'opr'  : '-',
    'left' : {'type': 'value', 'val': 5},
    'right': {
        'type' : 'binaryoperation',
        'opr'  : '*',
        'left' : {'type': 'value', 'val': 2},
        'right': {'type': 'value', 'val': 3},
        },
    })) == 11, "evaluation failes!"

# Question 4 (++)
# explore the `delay` keyword in Golang, etc. and think about its difference between decorators
# can you implement a delay operator in Python?


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

"""This simple tool is help me to track weather changes which can affect to my
efficiency. Retrieve weather and pressure every hour. Works only on Windows."""

# Last time modified at 22-mar-2017 by Gudkov Alexey

from urllib import request
from bs4 import BeautifulSoup
import time
import os

# Separete old and new data with this border
border = '*' * 50
# Log file path
path = os.environ['USERPROFILE'] + '\\Documents\\weather.log'

def load_data():
        """Load old data from log file"""
        old_data = []
        # Copy data from log file to list
        try:
                with open(path, encoding='utf8') as file:
                        for string in file:
                                old_data.append(string[:-1])
        except FileNotFoundError:
                f = open(path, 'a', encoding='utf8')
                f.close()
        # Printing previous records
        try:
                for string in old_data[-5:]:
                        print(string)
        except IndexError:
                pass
        # Make new log file if strings count more than 50
        # but leave last five
        if len(old_data) >= 50:
                with open(path, 'w', encoding='utf8') as file:
                        for string in old_data[-5:]:
                                file.write(string + '\n')

def writer(text):
        """Write data to logfile"""
        text = text + '\n'
        with open(path, 'a', encoding='utf8') as file:
                file.write(text)

def weater_parse():
        """Retrieve weather from gismeteo"""
        # Make request
        r = request.urlopen('https://gismeteo.ru/')
        # Save page as string
        page = ''
        for string in r:
            page += string.decode('utf8')
        # Build soup
        soup = BeautifulSoup(page, 'html.parser')
        span = soup.find_all('span')
        # Searching for temperature
        for string in span:
            try:
                if 'val_to_convert' in string['class']:
                    temp = string.text.strip()
                    break
            except KeyError:
                pass
        # Find all div tags
        div = soup.find_all('div')
        # Searching for pressure
        for string in div:
            try:
                if 'info_value' in string['class']\
                   and 'мм рт. ст.' in string.text.strip():
                    pressure = string.text.strip()
                    break
            except KeyError:
                pass
        result = time.strftime("%d %B: ") + time.strftime("%H:%M ") + temp + \
                 ' pressure:' + pressure
        writer(result)
        return result

def main():
        print('Old data')
        load_data()
        print(border)
        print('Actual info:')
        while True:
                # Retrieve data every hour
                print(weater_parse())
                time.sleep(3600)

if __name__ == '__main__':
        main()


import numpy as np

class adaboost():
	def __init__(self,n_estimaters=10):
		self.n_estimaters=n_estimaters
		self.classifier_param=[]
		self.classifier_weights=[]

	def fit(self,data_x,data_y):
		m,n=np.shape(data_x)
		self.data_x=np.array(data_x)
		self.data_y=np.array(data_y)
		#初始化训练数据权值分布
		self.data_distribution=np.array([1/m]*m)

		for i in range(self.n_estimaters):
			rslt,a_m=self._get_primary_classifier()
			self._distribution_adjust(a_m,rslt)
			class_rslt=self.predict(self.data_x)
			class_rslt[class_rslt==-1]=0
			acc=self._accuracy_cal(self.data_y,class_rslt)
			print(acc)
			if acc>0.9999:break
		print(self.classifier_param)

	def predict(self,data_x):
		#根据基分类器进行预测
		m=len(data_x)
		class_rslt_vec=None

		for i in range(len(self.classifier_param)):
			feat_idx=self.classifier_param[i][0]
			val=self.classifier_param[i][1]
			tmp=[]
			if self.classifier_param[i][2]=='lower':
				tmp.append(data_x[:,feat_idx]<val)
				tmp=np.array(tmp,dtype=int)
				tmp[tmp==False]=-1
				if type(class_rslt_vec)!=np.ndarray:
					class_rslt_vec=tmp
				else:
					class_rslt_vec=np.vstack((class_rslt_vec,tmp))
			else:
				tmp.append(data_x[:,feat_idx]>val)
				tmp=np.array(tmp,dtype=int)
				tmp[tmp==False]=-1
				if type(class_rslt_vec)!=np.ndarray:
					class_rslt_vec=tmp
				else:
					class_rslt_vec=np.vstack((class_rslt_vec,tmp))

		class_rslt=np.mat(class_rslt_vec)
		#print(class_rslt)
		m=len(self.classifier_weights)
		weights=np.mat(self.classifier_weights)
		rslt=np.dot(weights,class_rslt)
		rslt=np.sign(rslt)
		return rslt

	def _get_primary_classifier(self):
		#基学习器训练
		m,n=np.shape(self.data_x)
		min_em=np.inf
		feat_idx=-1
		feat_val=0
		lower_upper=None
		rslt=[]

		for i in range(n):
			candi=np.unique(self.data_x[:,i],axis=0)
			candi=np.append(candi,candi.min()-1)
			candi=np.append(candi,candi.max()+1)
			val_candidate=np.sort(candi)

			#寻找使加权错误率最小的基学习器
			for val in val_candidate:
				class_vec_lower=np.array(self.data_x[:,i]<val)
				class_vec_upper=np.array(self.data_x[:,i]>val)
				e_m_lower_vec=np.not_equal(class_vec_lower,self.data_y)
				e_m_lower=np.sum(e_m_lower_vec*self.data_distribution)
				e_m_upper_vec=np.not_equal(class_vec_upper,self.data_y)
				e_m_upper=np.sum(e_m_upper_vec*self.data_distribution)
				if e_m_lower<min_em:
					feat_idx=i
					feat_val=val
					lower_upper='lower'
					rslt=e_m_lower_vec
					min_em=e_m_lower
				if e_m_upper<min_em:
					feat_idx=i
					feat_val=val
					lower_upper='upper'
					rslt=e_m_upper_vec
					min_em=e_m_upper
		a_m=1/2*np.log((1-min_em)/min_em)
		self.classifier_param.append([feat_idx,feat_val,lower_upper])
		self.classifier_weights.append(a_m)
		return rslt,a_m

	def _distribution_adjust(self,a_m,rslt):
		for i in range(len(self.data_x)):
			if rslt[i]==False:
				self.data_distribution[i]*=np.exp(-a_m)
			else:
				self.data_distribution[i]*=np.exp(a_m)
		self.data_distribution=self.data_distribution/np.sum(self.data_distribution)

	def _accuracy_cal(self,data_y,predict):
		rslt=np.equal(data_y,predict)
		return rslt.mean()

if __name__=='__main__':
	data_x=[[0,1,3],[0,3,1],[1,2,2],[1,1,3],[1,2,3],[0,1,2],[1,1,2],[1,1,1],[1,3,1],[0,2,1]]
	data_y=[0,0,0,0,0,0,1,1,0,0]

	#data_x=[[0],[1],[2],[3],[4],[5],[6],[7],[8],[9]]
	#data_y=[1,1,1,0,0,0,1,1,1,0]
	clf=adaboost()
	clf.fit(data_x,data_y)


########################################################################################################
# The RWKV Language Model - https://github.com/BlinkDL/RWKV-LM
########################################################################################################

import math
import logging
import torch
import torch.nn as nn
from torch.nn import functional as F
logger = logging.getLogger(__name__)

########################################################################################################
# RWKV: RWKV Time-mix + RWKV Channel-mix
########################################################################################################

class RWKV_TimeMix(nn.Module):
    def __init__(self, config, layer_id):
        super().__init__()
        assert config.n_embd % config.n_head == 0
        self.layer_id = layer_id
        self.ctx_len = config.ctx_len
        self.n_head = config.n_head
        self.head_size = config.n_embd // config.n_head

        self.time_w = nn.Parameter(torch.ones(self.n_head, config.ctx_len))
        self.time_alpha = nn.Parameter(torch.ones(self.n_head, 1, config.ctx_len))
        self.time_beta = nn.Parameter(torch.ones(self.n_head, config.ctx_len, 1))
        self.time_gamma = nn.Parameter(torch.ones(config.ctx_len, 1))
        self.register_buffer("mask", torch.tril(torch.ones(config.ctx_len, config.ctx_len)))

        self.time_shift = nn.ZeroPad2d((0,0,1,0))

        self.key = nn.Linear(config.n_embd, config.n_embd)
        self.value = nn.Linear(config.n_embd, config.n_embd)
        self.receptance = nn.Linear(config.n_embd, config.n_embd)

        self.output = nn.Linear(config.n_embd, config.n_embd)

    def forward(self, x):
        B, T, C = x.size()
        TT = self.ctx_len
        w = F.pad(self.time_w, (0, TT))
        w = torch.tile(w, [TT])
        w = w[:, :-TT].reshape(-1, TT, 2 * TT - 1)
        w = w[:, :, TT-1:] # w is now a circulant matrix
        w = w[:, :T, :T] * self.time_alpha[:, :, :T] * self.time_beta[:, :T, :]
        w = w.masked_fill(self.mask[:T, :T] == 0, 0)

        x = torch.cat([self.time_shift(x)[:, :-1, :C//2], x[:, :, C//2:]], dim = -1)
        k = self.key(x)
        v = self.value(x)
        r = self.receptance(x)

        k = torch.exp(k)
        sum_k = torch.cumsum(k, dim=1)

        kv = (k * v).view(B, T, self.n_head, self.head_size)

        wkv = (torch.einsum('htu,buhc->bthc', w, kv)).contiguous().view(B, T, C)

        rwkv = torch.sigmoid(r) * wkv / sum_k

        return self.output(rwkv) * self.time_gamma[:T, :]

class RWKV_ChannelMix(nn.Module):
    def __init__(self, config, layer_id):
        super().__init__()
        self.layer_id = layer_id
        self.time_shift = nn.ZeroPad2d((0,0,1,0))

        hidden_sz = 5 * config.n_embd // 2 # can use smaller hidden_sz because of R
        self.key = nn.Linear(config.n_embd, hidden_sz)
        self.value = nn.Linear(config.n_embd, hidden_sz)
        self.weight = nn.Linear(hidden_sz, config.n_embd)
        self.receptance = nn.Linear(config.n_embd, config.n_embd)

    def forward(self, x):
        B, T, C = x.size()

        x = torch.cat([self.time_shift(x)[:, :-1, :C//2], x[:, :, C//2:]], dim = -1)
        k = self.key(x)
        v = self.value(x)
        r = self.receptance(x)

        wkv = self.weight(F.mish(k) * v) # seems mish is a bit better than gelu

        rwkv = torch.sigmoid(r) * wkv

        return rwkv

########################################################################################################
# MHA_rotary: Multi-head Attention + Rotary Encoding + GeGLU FFN
########################################################################################################

class RotaryEmbedding(torch.nn.Module):
    def __init__(self, dim, base=10000):
        super().__init__()
        inv_freq = 1. / (base ** (torch.arange(0, dim, 2).float() / dim))
        self.register_buffer('inv_freq', inv_freq)
        self.seq_len_cached = None
        self.cos_cached = None
        self.sin_cached = None

    def forward(self, x, seq_len=None):
        if seq_len != self.seq_len_cached:
            self.seq_len_cached = seq_len
            t = torch.arange(seq_len, device=x.device)
            freqs = torch.einsum('i,j->ij', t, self.inv_freq)
            emb = torch.cat((freqs, freqs), dim=-1).to(x.device)
            self.cos_cached = emb.cos()
            self.sin_cached = emb.sin()
        return self.cos_cached, self.sin_cached

def rotate_half(x):
    x1, x2 = x[..., :x.shape[-1] // 2], x[..., x.shape[-1] // 2:]
    return torch.cat((-x2, x1), -1)

@torch.jit.script
def apply_rotary_pos_emb(q, k, cos, sin):
    cos, sin = cos[...,:q.shape[2],:], sin[...,:q.shape[2],:]
    return (q * cos) + (rotate_half(q) * sin), (k * cos) + (rotate_half(k) * sin)

class MHA_rotary(nn.Module):
    def __init__(self, config, layer_id, time_shift = False):
        super().__init__()
        self.layer_id = layer_id
        assert config.n_embd % config.n_head == 0
        self.n_head = config.n_head
        self.ctx_len = config.ctx_len
        self.head_size = config.n_embd // config.n_head

        if time_shift:
            self.time_shift = nn.ZeroPad2d((0,0,1,0))

        self.query = nn.Linear(config.n_embd, config.n_embd)
        self.key = nn.Linear(config.n_embd, config.n_embd)
        self.value = nn.Linear(config.n_embd, config.n_embd)

        self.register_buffer("mask", torch.tril(torch.ones(config.ctx_len, config.ctx_len)))

        self.rotary_ndims = int(self.head_size * 0.5)
        self.rotary_emb = RotaryEmbedding(self.rotary_ndims)

        self.output = nn.Linear(config.n_embd, config.n_embd)

    def forward(self, x):
        B, T, C = x.size()

        if hasattr(self, 'time_shift'):
            x = torch.cat([self.time_shift(x)[:, :-1, :C//2], x[:, :, C//2:]], dim = -1)

        q = self.query(x).view(B, T, self.n_head, self.head_size).transpose(1, 2)       # (B, T, C) -> (B, nh, T, hs)
        k = self.key(x).view(B, T, self.n_head, self.head_size).transpose(1, 2)         # (B, T, C) -> (B, nh, T, hs)
        v = self.value(x).view(B, T, self.n_head, self.head_size).transpose(1, 2)       # (B, T, C) -> (B, nh, T, hs)

        q, query_pass = q[..., :self.rotary_ndims], q[..., self.rotary_ndims:]
        k, key_pass = k[..., :self.rotary_ndims], k[..., self.rotary_ndims:]
        cos, sin = self.rotary_emb(q, seq_len=T)
        q, k = apply_rotary_pos_emb(q, k, cos, sin)                                     # rotary encoding
        q = torch.cat((q, query_pass), dim=-1)
        k = torch.cat((k, key_pass), dim=-1)

        att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))                 # self-attention: (B, nh, T, hs) * (B, nh, hs, T) -> (B, nh, T, T)
        att = att.masked_fill(self.mask[:T,:T] == 0, float('-inf'))                     # causal mask
        att = F.softmax(att, dim = -1)                                                  # softmax

        x = att @ v                                                                     # (B, nh, T, T) * (B, nh, T, hs) -> (B, nh, T, hs)
        x = x.transpose(1, 2).contiguous().view(B, T, C)                                # (B, nh, T, hs) -> (B, T, nh, hs) -> (B, T, C)

        x = self.output(x)
        return x

class GeGLU(torch.nn.Module):
    def __init__(self, config, layer_id, time_shift = False):
        super().__init__()
        self.layer_id = layer_id

        if time_shift:
            self.time_shift = nn.ZeroPad2d((0,0,1,0))

        hidden_sz = 3 * config.n_embd
        self.key = nn.Linear(config.n_embd, hidden_sz)
        self.value = nn.Linear(config.n_embd, hidden_sz)
        self.weight = nn.Linear(hidden_sz, config.n_embd)

    def forward(self, x):
        B, T, C = x.size()
        if hasattr(self, 'time_shift'):
            x = torch.cat([self.time_shift(x)[:, :-1, :C//2], x[:, :, C//2:]], dim = -1)

        k = self.key(x)
        v = self.value(x)
        y = self.weight(F.gelu(k) * v)
        return y

########################################################################################################
# MHA_pro: with more tricks
########################################################################################################

class MHA_pro(nn.Module):
    def __init__(self, config, layer_id):
        super().__init__()
        self.layer_id = layer_id
        assert config.n_embd % config.n_head == 0
        self.n_head = config.n_head
        self.ctx_len = config.ctx_len
        self.head_size = config.n_embd // config.n_head

        self.time_w = nn.Parameter(torch.ones(self.n_head, config.ctx_len))
        self.time_alpha = nn.Parameter(torch.ones(self.n_head, 1, config.ctx_len))
        self.time_beta = nn.Parameter(torch.ones(self.n_head, config.ctx_len, 1))
        self.time_gamma = nn.Parameter(torch.ones(config.ctx_len, 1))
        self.register_buffer("mask", torch.tril(torch.ones(config.ctx_len, config.ctx_len)))

        self.time_shift = nn.ZeroPad2d((0,0,1,0))
        self.query = nn.Linear(config.n_embd, config.n_embd)
        self.key = nn.Linear(config.n_embd, config.n_embd)
        self.value = nn.Linear(config.n_embd, config.n_embd)

        self.rotary_ndims = int(self.head_size * 0.5)
        self.rotary_emb = RotaryEmbedding(self.rotary_ndims)

        self.head_mix = nn.Conv2d(self.n_head, self.n_head, kernel_size=1, bias=False)  # talking heads

        self.output = nn.Linear(config.n_embd, config.n_embd)

    def forward(self, x):
        B, T, C = x.size()
        TT = self.ctx_len
        w = F.pad(self.time_w, (0, TT))
        w = torch.tile(w, [TT])
        w = w[:, :-TT].reshape(-1, TT, 2 * TT - 1)
        w = w[:, :, TT-1:] # w is now a circulant matrix
        w = w[:, :T, :T] * self.time_alpha[:, :, :T] * self.time_beta[:, :T, :]

        x = torch.cat([self.time_shift(x)[:, :-1, :C//2], x[:, :, C//2:]], dim = -1)    # time-shift mixing
        q = self.query(x).view(B, T, self.n_head, self.head_size).transpose(1, 2)       # (B, T, C) -> (B, nh, T, hs)
        k = self.key(x).view(B, T, self.n_head, self.head_size).transpose(1, 2)         # (B, T, C) -> (B, nh, T, hs)
        v = self.value(x).view(B, T, self.n_head, self.head_size).transpose(1, 2)       # (B, T, C) -> (B, nh, T, hs)

        q, query_pass = q[..., :self.rotary_ndims], q[..., self.rotary_ndims:]
        k, key_pass = k[..., :self.rotary_ndims], k[..., self.rotary_ndims:]
        cos, sin = self.rotary_emb(q, seq_len=T)
        q, k = apply_rotary_pos_emb(q, k, cos, sin)                                     # rotary encoding
        q = torch.cat((q, query_pass), dim=-1)
        k = torch.cat((k, key_pass), dim=-1)

        att = (q @ k.transpose(-2, -1)) * (1.0 / math.sqrt(k.size(-1)))                 # self-attention: (B, nh, T, hs) * (B, nh, hs, T) -> (B, nh, T, T)
        att = att.masked_fill(self.mask[:T,:T] == 0, float('-inf'))                     # causal mask
        att = F.softmax(att, dim = -1)                                                  # softmax
        att = att * w                                                                   # time-weighting
        att = self.head_mix(att)                                                        # talking heads

        x = att @ v                                                                     # (B, nh, T, T) * (B, nh, T, hs) -> (B, nh, T, hs)
        x = x.transpose(1, 2).contiguous().view(B, T, C)                                # (B, nh, T, hs) -> (B, T, nh, hs) -> (B, T, C)

        x = self.output(x) * self.time_gamma[:T, :]
        return x

########################################################################################################
# The GPT Model with our blocks
########################################################################################################

class LabelSmoothingCrossEntropy(nn.Module): # can avoid nan loss
    def __init__(self, smoothing=0.0):
        super().__init__()
        self.confidence = 1.0 - smoothing
        self.smoothing = smoothing

    def forward(self, pred, target):
        pred = pred.log_softmax(dim=-1)
        with torch.no_grad():
            true_dist = torch.zeros_like(pred)
            true_dist.fill_(self.smoothing / (pred.size(-1) - 1))
            true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)
        return torch.mean(torch.sum(-true_dist * pred, dim=-1))

class RMSNorm(nn.Module):
    def __init__(self, d):
        super().__init__()
        self.dd = d ** (-1. / 2)
        self.weight = nn.Parameter(torch.ones(d))

    def forward(self, x):
        norm_x = x.norm(2, dim=-1, keepdim=True)
        x_normed = x / (norm_x * self.dd + 1e-12)
        return self.weight * x_normed

class FixedNorm(nn.Module):
    def __init__(self, d):
        super().__init__()
        self.dd = d ** (-1. / 2)

    def forward(self, x):
        norm_x = x.norm(2, dim=-1, keepdim=True)
        x_normed = x / (norm_x * self.dd + 1e-12)
        return x_normed

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

class GPTConfig:
    def __init__(self, vocab_size, ctx_len, **kwargs):
        self.vocab_size = vocab_size
        self.ctx_len = ctx_len
        for k,v in kwargs.items():
            setattr(self, k, v)

class Block(nn.Module):
    def __init__(self, config, layer_id):
        super().__init__()

        self.ln1 = nn.LayerNorm(config.n_embd)
        self.ln2 = nn.LayerNorm(config.n_embd)

        if config.model_type == 'RWKV':
            self.attn = RWKV_TimeMix(config, layer_id)
            self.mlp = RWKV_ChannelMix(config, layer_id)

        elif config.model_type == 'MHA_rotary':
            self.attn = MHA_rotary(config, layer_id)
            self.mlp = GeGLU(config, layer_id)

        elif config.model_type == 'MHA_shift':
            self.attn = MHA_rotary(config, layer_id, time_shift=True)
            self.mlp = GeGLU(config, layer_id, time_shift=True)

        elif config.model_type == 'MHA_pro':
            self.attn = MHA_pro(config, layer_id)
            self.mlp = RWKV_ChannelMix(config, layer_id)

    def forward(self, x):

        x = x + self.attn(self.ln1(x))
        x = x + self.mlp(self.ln2(x))

        return x

class GPT(nn.Module):
    def __init__(self, config):
        super().__init__()
        self.config = config

        self.tok_emb = nn.Embedding(config.vocab_size, config.n_embd)

        self.blocks = nn.Sequential(*[Block(config, i) for i in range(config.n_layer)])

        self.ln_f = nn.LayerNorm(config.n_embd)
        self.head = nn.Linear(config.n_embd, config.vocab_size, bias=False)

        self.ctx_len = config.ctx_len
        self.apply(self._init_weights)

        if self.config.model_type == 'RWKV': # improve orthogonal weight init
            ww = self.state_dict()
            for k in ww:
                if 'tok_emb' in k:
                    if self.config.vocab_size > self.config.n_embd:
                        ww[k] *= math.sqrt(self.config.vocab_size)
                    else:
                        ww[k] *= math.sqrt(self.config.n_embd)
                    ww[k] *= 0.4 # 0.4 is a safe choice // 0.8 might works better for chinese
                elif 'head.weight' in k:
                    ww[k] *= 0.4 # 0.4 is a safe choice // 0.8 might works better for chinese
                elif 'blocks.' in k:
                    block_id = int(k.split('.')[1])
                    if 'receptance.weight' in k:
                        ww[k] *= 0 # 0 works the best
                    elif 'attn.key.weight' in k:
                        ww[k] *= 0 # 0 works the best
                    elif 'attn.output.weight' in k:
                        ww[k] *= 1 / pow(1+block_id, 0.5) # 0.5 ~ 0.7 gives similar results
                    elif 'mlp.weight.weight' in k:
                        ww[k] *= 1 / pow(1+block_id, 0.5) # 0.5 ~ 0.7 gives similar results

        logger.info("number of parameters: %e", sum(p.numel() for p in self.parameters()))

    def get_ctx_len(self):
        return self.ctx_len

    def _init_weights(self, module):
        if isinstance(module, (nn.Linear, nn.Embedding)):
            if self.config.model_type == 'RWKV':
                gain = 1.0
                if isinstance(module, nn.Linear):
                    if module.weight.data.shape[0] > module.weight.data.shape[1]:
                        gain = math.sqrt(module.weight.data.shape[0] / module.weight.data.shape[1])
                nn.init.orthogonal_(module.weight, gain=gain)
            else:
                module.weight.data.normal_(mean=0.0, std=0.01)

        if isinstance(module, nn.Linear) and module.bias is not None:
            module.bias.data.zero_()

    def configure_optimizers(self, train_config):
        # separate out all parameters to those that will and won't experience regularizing weight decay
        decay = set()
        no_decay = set()

        whitelist_weight_modules = (nn.Linear, )
        blacklist_weight_modules = (RMSNorm, nn.LayerNorm, nn.Embedding)
        for mn, m in self.named_modules():
            for pn, p in m.named_parameters():
                fpn = '%s.%s' % (mn, pn) if mn else pn # full param name

                if pn.endswith('bias') or ('time' in fpn) or ('head' in fpn):
                    no_decay.add(fpn)
                elif pn.endswith('weight') and isinstance(m, whitelist_weight_modules):
                    decay.add(fpn)
                elif pn.endswith('weight') and isinstance(m, blacklist_weight_modules):
                    no_decay.add(fpn)

        # validate that we considered every parameter
        param_dict = {pn: p for pn, p in self.named_parameters()}
        inter_params = decay & no_decay
        union_params = decay | no_decay
        assert len(inter_params) == 0, "parameters %s made it into both decay/no_decay sets!" % (str(inter_params), )
        assert len(param_dict.keys() - union_params) == 0, "parameters %s were not separated into either decay/no_decay set!" \
                                                    % (str(param_dict.keys() - union_params), )

        optim_groups = [
            {"params": [param_dict[pn] for pn in sorted(list(decay))], "weight_decay": train_config.weight_decay},
            {"params": [param_dict[pn] for pn in sorted(list(no_decay))], "weight_decay": 0.0},
        ]
        optimizer = torch.optim.AdamW(optim_groups, lr=train_config.learning_rate, betas=train_config.betas)
        return optimizer

    def forward(self, idx, targets=None):
        B, T = idx.size()
        assert T <= self.ctx_len, "Cannot forward, because len(input) > model ctx_len."

        x = self.tok_emb(idx)

        x = self.blocks(x)

        x = self.ln_f(x)
        x = self.head(x)

        loss = None
        if targets is not None:
            loss = LabelSmoothingCrossEntropy(smoothing=1e-6)(x.view(-1, x.size(-1)), targets.view(-1)) # try increasing smoothing if you see nan

        return x, loss


from psycopg2 import ProgrammingError
from psycopg2.extras import execute_batch

_NO_ARG = object()

class Querier:
    def __init__(self, connect, debug_log=None, cursor_factory=None, **kwargs):
        self.connect = connect
        self.debug_log = debug_log
        self.cursor_factory = cursor_factory
        self.kwargs = kwargs
        self._entered = False

    def __enter__(self):
        self._conn = self.connect()
        self._entered = True
        return self

    # noinspection PyBroadException
    def __exit__(self, *args):
        try:
            self._entered = False
            self._conn.close()
        except Exception:
            pass

    def query(self, query, debug_log=_NO_ARG, cursor_factory=_NO_ARG, **kwargs):
        with self.transaction(cursor_factory) as tr:
            return tr.query(query, debug_log, **kwargs)

    def query_many(self, query, argslist, debug_log=_NO_ARG, **kwargs):
        with self.transaction() as tr:
            tr.query_many(query, argslist, debug_log, **kwargs)

    def query_external(self, fname, start=None, end=None, debug_log=_NO_ARG, **kwargs):
        with self.transaction() as tr:
            tr.query_external(fname, start, end, debug_log, **kwargs)

    def callproc(self, procname, parameters=_NO_ARG, debug_log=_NO_ARG, **kwargs):
        with self.transaction() as tr:
            tr.callproc(procname, parameters, debug_log, **kwargs)

    def dump_to_csv(self, query, fname, debug_log=_NO_ARG, **kwargs):
        with self.transaction() as tr:
            tr.dump_to_csv(query, fname, debug_log, **kwargs)

    def load_from_csv(self, table, fname, header=True, debug_log=_NO_ARG, **kwargs):
        with self.transaction() as tr:
            tr.load_from_csv(table, fname, header, debug_log, **kwargs)

    def transaction(self, cursor_factory=_NO_ARG, **kwargs):
        return Transaction(self, cursor_factory, **kwargs)

    def vacuum(self, table, analyze=False, **kwargs):
        with self.connect() as conn:
            conn.autocommit = True
            cur = conn.cursor(cursor_factory=self.cursor_factory)
            full_kwargs = dict(self.kwargs)
            full_kwargs.update(kwargs)
            query = "vacuum analyze {}" if analyze else "vacuum {}"
            query = query.format(table).format(**full_kwargs)
            cur.execute(query)

class Transaction:
    def __init__(self, querier, cursor_factory, **kwargs):
        self._querier = querier
        if cursor_factory is _NO_ARG:
            cursor_factory = querier.cursor_factory
        self._cursor_factory = cursor_factory
        self._kwargs = kwargs
        self._collapsed_entry = False

    def __enter__(self):
        if not self._querier._entered:
            self._querier.__enter__()
            self._collapsed_entry = True
        self._conn = self._querier._conn
        self._conn.__enter__()
        self._cur = self._conn.cursor(cursor_factory=self._cursor_factory)
        self._cur.__enter__()
        return self

    # noinspection PyBroadException
    def __exit__(self, *args):
        try:
            try:
                self._cur.__exit__(*args)
            finally:
                try:
                    self._conn.__exit__(*args)
                finally:
                    if self._collapsed_entry:
                        self._querier.__exit__(*args)
        except Exception:
            pass

    def query(self, query, debug_log=_NO_ARG, **kwargs):
        kwargs = self._full_kwargs(kwargs)
        debug_log = self._real_debug_log(debug_log)
        query = query.format(**kwargs)

        debug_log.log("Executing query:")
        debug_log.log(self._cur.mogrify(query, kwargs).decode())
        self._draw_line(debug_log)

        self._cur.execute(query, kwargs)
        try:
            result = self._cur.fetchall()
            return result
        except ProgrammingError:
            return None

    def query_many(self, query, argslist, debug_log=_NO_ARG, **kwargs):
        kwargs = self._full_kwargs(kwargs)
        debug_log = self._real_debug_log(debug_log)
        query = query.format(**kwargs)

        debug_log.log("Executing batch query:")
        debug_log.log(query)
        self._draw_line(debug_log)

        execute_batch(self._cur, query, argslist)

    def query_external(self, fname, start=None, end=None, debug_log=_NO_ARG, **kwargs):
        result = None

        with open(fname, encoding="utf-8-sig") as fin:
            lines = list(fin)
            it = iter(lines)
            if start is not None:
                for line in it:
                    line = line.strip()
                    if line.startswith("--"):
                        line = line[2:].strip()
                        if line == start:
                            break

            finished = False
            while not finished:
                query = ""
                for line in it:
                    if line.startswith("--"):
                        if end is not None:
                            comment = line[2:].strip()
                            if comment == end:
                                finished = True
                                break
                    else:
                        if line.strip():
                            query += line
                else:
                    finished = True

                if not query.strip():
                    continue

                new_result = self.query(query, debug_log, **kwargs)
                if new_result is not None:
                    result = new_result

        return result

    def callproc(self, procname, parameters=_NO_ARG, debug_log=_NO_ARG, **kwargs):
        kwargs = self._full_kwargs(kwargs)
        debug_log = self._real_debug_log(debug_log)
        if parameters is _NO_ARG:
            parameters = []
        procname = procname.format(**kwargs)

        debug_log.log("Calling procedure {} with parameters {}".format(procname, parameters))
        self._draw_line(debug_log)

        self._cur.callproc(procname, parameters)

    def dump_to_csv(self, query, fname, debug_log=_NO_ARG, **kwargs):
        kwargs = self._full_kwargs(kwargs)
        debug_log = self._real_debug_log(debug_log)
        query = self._cur.mogrify(query.format(**kwargs), kwargs).decode()
        fname = fname.format(**kwargs)

        debug_log.log("Dumping to file {} results of query:".format(fname))
        debug_log.log(query)
        self._draw_line(debug_log)

        with open(fname, "w") as outf:
            self._cur.copy_expert(
                    "copy ({}) to stdout csv header".format(query), outf)

    def load_from_csv(self, table, fname, header=True, debug_log=_NO_ARG, **kwargs):
        kwargs = self._full_kwargs(kwargs)
        debug_log = self._real_debug_log(debug_log)
        table = table.format(**kwargs)
        fname = fname.format(**kwargs)

        debug_log.log("Loading file {} into table {}".format(fname, table))
        self._draw_line(debug_log)

        with open(fname, "r") as outf:
            self._cur.copy_expert(
                    "copy {} from stdin csv{}".format(table, " header" if header else ""), outf)

    def _full_kwargs(self, kwargs):
        full_kwargs = dict(self._querier.kwargs)
        full_kwargs.update(self._kwargs)
        full_kwargs.update(kwargs)
        return full_kwargs

    def _real_debug_log(self, debug_log):
        if debug_log is _NO_ARG:
            debug_log = self._querier.debug_log
        if debug_log is None:
            debug_log = NullLogger()
        return debug_log

    @staticmethod
    def _draw_line(debug_log):
        return debug_log.log("-" * 80)

class NullLogger:
    def log(self, text):
        pass


class Myclass(object):
	pass

this_obj = Myclass()

print(this_obj)

that_obj = Myclass()

print(that_obj)

#Haxcode is different

class Myclass(object):
	var = 10

this_obj = Myclass()
that_obj = Myclass()
print(this_obj.var)
print(that_obj.var)

class Joe(object):
	greeting = 'Hello Joe'

	def callme(self):
		print('calling "callme" method with instance: ')
		print(self)

thisjoe = Joe()

print(thisjoe.greeting)

thisjoe.callme()
print(thisjoe)

#Instance methods are variables defined in the class
#They are accessed through the instance: instance.method()

import random

class Myclass(object):
	def dothis(self):
		self.rand_val = random.randint(1.10)

myint = Myclass()
myint.dothis()
print(myint.rand_val)

#Encapsulation
#ensure data integrity

class MyInteger(object):
	def __init__(self):
		print('calling __init__')
		self.val = 0

	def set_val(self, val):
		try:
			val = int(val)
		except ValueError:
			return
		self.val = val

	def get_val(self):
		return self.val

	def increment_val(self):
		self.val = self.val + 1

num = MyInteger()
num.set_val('hi')
num.set_val(5)
print(num.get_val())
print(num.increment_val())

class InstanceCounter(object):
	count = 0

	def __init__(self, val):
		self.val = val
		InstanceCounter.count += 1

	def set_val(self, newval):
		self.val = newval

	def get_val(self):
		return self.val

	def get_count(self):
		return InstanceCounter.count

a = InstanceCounter(5)
b = InstanceCounter(6)
c = InstanceCounter(7)

for obj in (a,b,c):
	print('val of obj: %s'%(obj.get_val()))
	print('count: %s'%(obj.get_count()))


from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from app.models import Attendance
from app.utils import slice_by
from datetime import datetime, timedelta
from flask import current_app

import copy
import calendar
import pytz
import os
import time

def draw_row(srno, draw, student, month):
    font = ImageFont.truetype("app/static/fonts/Ubuntu-M.ttf", 60)
    text_y = 25
    vals = []

    # Index
    col_width = 170
    text_width, text_height = draw.textsize(str(srno), font=font)
    text_x = 230 + (col_width - text_width) / 2
    draw.text((text_x, text_y), str(srno), font=font)

    # Category
    draw.text((460, text_y), student.category.name, font=font)

    # Name
    draw.text((850, text_y), student.name, font=font)

    # Attendace
    # Start position
    x_offset = 1870
    col_width = 140
    col_gap = 7

    _, no_of_days = calendar.monthrange(month.year, month.month)
    for d in range(1, 32):
        if d <= no_of_days:
            curr_date = month + timedelta(days=d - 1)
            attendance = Attendance.query.filter_by(
                student_id=student.id, date=curr_date
            ).first()
            val = " "
            if attendance and attendance.punch_in and attendance.punch_in.strip():
                val = "P"
            vals.append(val)
            text_width, text_height = draw.textsize(val, font=font)
            text_x = x_offset + (col_width - text_width) / 2
            draw.text((text_x, text_y), val, font=font)
        x_offset += col_width + col_gap

    # Total A and P
    total_a = sum([v == " " for v in vals])
    total_p = sum([v == "P" for v in vals])

    col_width = 141
    text_width, text_height = draw.textsize(str(total_p), font=font)
    text_x = x_offset + (col_width - text_width) / 2
    draw.text((text_x, text_y), str(total_p), font=font)

    x_offset += col_width + col_gap

    col_width = 173
    text_width, text_height = draw.textsize(str(total_a), font=font)
    text_x = x_offset + (col_width - text_width) / 2
    draw.text((text_x, text_y), str(total_a), font=font)

def draw_header(header2, month, categories, branches):
    font = ImageFont.truetype("app/static/fonts/Ubuntu-M.ttf", 60)
    draw = ImageDraw.Draw(header2)
    # Group (Categories)
    draw.text((1175, 290), ", ".join([cat.name for cat in categories]), font=font)
    # Location (Branches)
    draw.text((4300, 290), ", ".join([b.name for b in branches]), font=font)
    # Time
    time = datetime.now(pytz.utc)
    time = time.astimezone(pytz.timezone("Asia/Kolkata"))
    draw.text((4300, 110), time.strftime("%I:%M:%S %p"), font=font)
    # Month at 6020,110
    draw.text((6020, 110), month.strftime("%B"), font=font)
    # YEAR at 6020,290
    draw.text((6020, 290), month.strftime("%Y"), font=font)

def buildReport(students, month, categories, branches):
    no_rows = int(os.environ.get("ATTENDANCE_MAX_STUDENTS", 24))
    month = datetime.strptime(month, "%d %B %Y")
    header1, header2, row, footer = map(
        Image.open,
        [
            "./monthly_report/header1.jpg",
            "./monthly_report/header2.jpg",
            "./monthly_report/row.jpg",
            "./monthly_report/footer.jpg",
        ],
    )

    max_width = max([item.size[0] for item in (header1, header2, row, footer)])

    total_height = sum([item.size[1] for item in (header1, header2, footer)])
    total_height += no_rows * row.size[1]
    sr_no = 1
    page_imgs = []
    for students in slice_by(students, no_rows):
        att_sheet = Image.new("RGB", (max_width, total_height))
        att_sheet.paste(header1, (0, 0))
        draw_header(header2, month, categories, branches)
        att_sheet.paste(header2, (0, header1.size[1]))
        y_offset = header1.size[1] + header2.size[1]
        for student in students:
            tmp_row = copy.deepcopy(row)
            draw_row(sr_no, ImageDraw.Draw(tmp_row), student, month)
            att_sheet.paste(tmp_row, (0, y_offset))
            y_offset += row.size[1]
            sr_no += 1
        # Adding blank rows if required
        if len(students) < no_rows:
            for _ in range(no_rows - len(students)):
                tmp_row = copy.deepcopy(row)
                att_sheet.paste(tmp_row, (0, y_offset))
                y_offset += row.size[1]
        att_sheet.paste(footer, (0, y_offset))
        # resize the image and app to list of pages
        att_sheet = att_sheet.resize(
            (att_sheet.size[0] // 5, att_sheet.size[1] // 5), Image.ANTIALIAS
        )
        page_imgs.append(att_sheet)
    report_path = current_app.config.get("REPORT_FOLDER")
    report_filename = "Attendance Report_{}.pdf".format(str(int(time.time())))
    report_filepath = os.path.join(report_path, report_filename)
    if len(page_imgs) > 0:
        page_imgs[0].save(
            report_filepath,
            "PDF",
            save_all=True,
            quality=100,
            append_images=page_imgs[1:],
        )
        return report_filepath


import datetime
#format long
import time
avg_delay=0
for i in range(1, 100):
        t_scan = datetime.datetime.now()
        t_scan_stamp = t_scan.timestamp()
        time.sleep(.1)
        t_pose = datetime.datetime.now()
        t_pose_stamp = t_pose.timestamp()
        avg_delay+=(t_pose_stamp - t_scan_stamp)
        print(i," : ", (t_pose_stamp - t_scan_stamp))
avg_delay=avg_delay/99
print("average delay = ", avg_delay)
print("t_scan : ", t_scan)
print ("t_pose : ", t_pose)


import os
import numpy as np

path = os.path.dirname(os.path.realpath(__file__))
os.chdir(path)
print(os.getcwd)

#Import Mission String

MS = np.genfromtxt('input_s1',names=True,dtype=float,delimiter='\t')

#--- Atmospheric data---
atmdat = np.genfromtxt('std_atm_data_1000.txt',names=True,dtype=float,delimiter='\t')
# (Altitude(km), Temperature(K), Pressure(Pa), Density(kg/m3))
alt_data = [atmdat[x][0] for x in range(len(atmdat))]
T_data = [atmdat[x][1] for x in range(len(atmdat))]
P_data = [atmdat[x][2] for x in range(len(atmdat))]
rho_data = [atmdat[x][3] for x in range(len(atmdat))]

delt = 0.01 # timestep, s
delt23 = 0.1 # timestep, s

# Constants
ftm=0.3048                  #Feet to meter conversion factor
gamma_air = 1.4
R_air = 287

#-------------------------------------Outputs-----------------------------------

pl = ['t','Q','h','am','vrm','fpa','r','aoa','steer[:,1]','event','mach','pr']

#-------------------------------Orbit parameters--------------------------------
r0 = [x*10**3 for x in [400,400]]               # [m] Orbit h
inclination = np.radians(90)                     # [deg] Orbit inclination

#------------------------------Vehicle parameters-------------------------------
mpl_req = 500                           # [kg] Payload mass
m_PLF = 150
m_PLA = 45
m_EB = 40
m_pl = mpl_req+m_PLA+m_EB+m_PLF
pload =[m_pl-m_PLF-m_PLA-m_EB,m_PLF,m_PLA,m_EB]
mis = [0, 0, 0]
Sp_imp = np.array([270, 310, 310])          # [s] Isp of stages
strf = np.array([0.15, 0.15, 0.15])  # [] Structural factors
m_lo = np.array([[], 50, 15])               # left out mass in kg
# segn = np.array([[], 20, 20])               # no. of pitchrate segments
# Thr = np.array([[], 20*1000*9.8055, 10*1000*9.8055])
tw_ratio = 2
dia = 2                                # [m] diameter of LV
area = np.pi*(dia/2)**2                    # [m2] CS area of LV
roll = 0
yaw = 0
pitch = 0
#-------------------------Vehicle Inputs---------------------------
#prate_in = ([[],np.radians(np.zeros(segn[1])),np.radians(np.zeros(segn[2]))])
Thr = np.array([[], 20*1000*9.8055, 4.2*1000*9.8055])
Ns = 3
#Thrust_in = [[],np.ones(segn[1])*20*1000*9.8055,np.ones(segn[2])*4.2*1000*9.8055]
#----------------------------Kickrate Maneuvre---------------------------------
#krate = radians(-1.5) #deg/s
kstart = 7.5 # s
kend = 20 # s
#prate_in = ([[],np.radians(np.random.rand(20)),np.radians(np.random.rand(20))])
#------------------------------Gravity Turn-------------------------------------
gtstart = 20 # s
gtend = 125.5 # s
#------------------------------Launch Pad parameters----------------------------
# Kulasekharapatnam
lat_L = np.radians(8.3989)                  # [rad], latitude
long_L = np.radians(78.0524)                # [rad], longitude
h0 = 8                             # [km] LP h above sea level (KSP)
# Sriharikotta
#lat_L = np.radians(13.7259)                 # [rad], latitude
#long_L = np.radians(80.2266)                # [rad], longitude
#h0 = 26.40                             # [km] LP h above sea level (SHAR)

#----------------------------- Earth Parameters --------------------------------
g0 = 9.80665 # acceleration due to gravity at surface of earth, m/s**2
Re = 2.0925741*ftm*(10**7) # Equitorial radius of earth in m
Rp = 2.0855590*ftm*(10**7) #Polar radius of earth in m
k_e = (Re/Rp)**2
Om_p = [0,0,7.2921159*(10**-5)] #Angular Velocity of earth in rad/sec
mu = 3.986004418*10**14                 # [m3/sec2] gravity parameter
j2 = 1.0823*10**-3                     # [] gravity parameter
f = (Re-Rp)/Re                         # [] Oblateness/Flattening
#-------------------------------Derived quantities------------------------------

apogee = max(r0)                        # [m] Apogee h
perigee = min(r0)                     # [m] Perigee h
k_e = (Re/Rp)**2
PhiL = np.arctan((1-f)**2*np.tan(lat_L));
Rs = Re/np.sqrt(1+(k_e-1)*(np.sin(PhiL))**2);
Ri = Rs+h0;
ri = [Ri*x for x in [np.cos(lat_L)*np.cos(long_L),np.cos(lat_L)*np.sin(long_L),np.sin(lat_L)]];
vi = np.cross(Om_p,ri);
alti = np.linalg.norm(ri) - Rs
IGL = np.array( [[-np.sin(lat_L)*np.cos(long_L), -np.sin(lat_L)*np.sin(long_L), np.cos(lat_L)],
            [-np.sin(long_L), np.cos(long_L), 0],
            [-np.cos(lat_L)*np.cos(long_L), -np.cos(lat_L)*np.sin(long_L), -np.sin(lat_L)]])
#AzL = np.arcsin(np.cos(inclination)/np.cos(lat_L)); # As per computation

AzL = np.radians(179.9)
# Azl = radians(135) # Launch azimuth for SHAR polar launches

#----------------------------Trajectory Determination---------------------------

# An estimate of the velocity required, as the actual velocity required
# depends on the final trajectory.

v_p = 0                                # [m/s] propulsive loss
margin_v = 3                       # [m/s] velocity margin for safety
v_sy = 0                               # [m/s] steering, yaw maneuver loss
a = (apogee+perigee)/2+Re              # [m] semi-major axis of orbit
v_o = np.sqrt(mu*(2/(Re+perigee)-1/a))   # [m/s] orbital velocity
v_rot = np.sqrt(np.dot(vi[0], vi[0]))     # [m/s] Earth's rotational velocity
v_rgain = v_o - np.sqrt(np.square(v_rot+v_o*np.sin(AzL))+np.square(v_o*np.cos(AzL)))

# as per Loftus and Teixeira empirical relation for gravity loss
v_g = 81.006*np.square(tw_ratio)-667.62*(tw_ratio)+1505.4

# as per Loftus and Teixeira empirical relation for drag loss
v_d = -32.692*np.square(tw_ratio)+258.86*tw_ratio-226.57

# ve_req = v_o+v_g+v_d+v_p+v_sy+v_rgain+margin_v
ve_req = 10.09*1e3
# print('Estimated velocity required : %f km/s\n',ve_req/1000)

# print('\n\nReading Mach no. vs Coeff of Drag data...\n')
#f=open("data.txt", "r")
#if f.mode == 'r':
#    data = f.read()
data = np.genfromtxt('data.txt',
                    names=True,
                    dtype=None,
                    delimiter='  ')
mach_data = [data[x][0] for x in range(len(data))]
cd_data = [data[x][1] for x in range(len(data))]
#mach_data = append([0],mach_data)
#cd_data = append([0],cd_data)
# print('Aerodynamic Data assimilated!\n\n')


import os
import re
from nltk.stem.porter import PorterStemmer
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords
from nltk import pos_tag
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score
from sklearn.naive_bayes import MultinomialNB
from nltk import tokenize
from nltk import word_tokenize

path = 'pos'
path1 = 'neg'
files = os.listdir(path)
files1 = os.listdir(path1)
import warnings
warnings.filterwarnings("ignore")

def vec_cv( ngr,m_df, dataset_train,dataset_test):
    cv = CountVectorizer(binary=False,ngram_range=ngr, min_df=m_df, max_df=0.85)
    X = cv.fit_transform(dataset_train)
    X_test = cv.transform(dataset_test)
    return cv, X, X_test

def vec_tdidf(ngr,m_df, dataset_train, dataset_test):
    tfidf = TfidfVectorizer(ngram_range=ngr, min_df=m_df, max_df=0.85)
    X = tfidf.fit_transform(dataset_train)
    X_test = tfidf.transform(dataset_test)
    return tfidf,X,X_test

def clasif_lr(c,X,y_train,y_train1, X_test):
    lr = LogisticRegression(C=c, solver='liblinear')
    lr.fit(X, y_train)
    y_predict = lr.predict(X_test)
    return  accuracy_score(y_train1, y_predict)

def classif_SVC(c,X,y_train,y_train1,X_test):
    svc = LinearSVC(C=c, max_iter=2000)
    svc.fit(X, y_train)
    y_predict = svc.predict(X_test)
    return accuracy_score(y_train1, y_predict)

def classif_NB(X,y_train,X_test,y_train1):
    nb = MultinomialNB()
    nb.fit(X, y_train)
    y_predict = nb.predict(X_test)
    return accuracy_score(y_train1, y_predict)

def get_positions(tokens, term):
    positions = []
    for i in range(len(tokens)):
        if tokens[i] == term:
            positions.append(i)
    return positions

def read_data(files, path):
    list_of_lists = []
    for file in files:
        f = open(path+'/'+file)
        data = f.read()
        stemmer = PorterStemmer()
        tokenizer = RegexpTokenizer(r'\w+')
        sentences = tokenize.sent_tokenize(data)
        '''
        term = 'not'
        sentences_tok = []
        for sentence in sentences:
            sentence_tok = word_tokenize(sentence)
            sublista = get_positions(sentence_tok, 'not')
            if (len(sublista) != 0):
                for elem in range(len(sublista)):
                    for poz in range(len(sentence_tok)):
                        if poz > sublista[elem]:
                            if (sentence_tok[poz] == ',') | (sentence_tok[poz] == ';') | (sentence_tok[poz] == ':') | (
                                    sentence_tok[poz] == '(') | (sentence_tok[poz] == ')'):
                                break
                            if sentence_tok[poz] == 'not':
                                sentence_tok[poz] = ' '
                            if 'NOT_' in sentence_tok[poz]:
                                sentence_tok[poz] = sentence_tok[poz][4:]
                            else:
                                sentence_tok[poz] = 'NOT_' + sentence_tok[poz]

            sentences_tok.append(" ".join(sentence_tok))
        sentence = ' '.join(sentences_tok)
        review_tok = tokenizer.tokenize(sentence)
        '''
        review_tok=data.split()
        #review_tok = tokenizer.tokenize(data)
        #stop = set(stopwords.words('english'))-{'no','not','not','don'}
        #review_stop = [w for w in review_tok if not w in stop]
        '''
        tagged_s = pos_tag(review_tok)
        for word in tagged_s:
            if (word[1] == 'NNP') | (word[1]=='NNPS'):
                tagged_s.remove(word)
        tagg_s = []
        for word in tagged_s:
            tagg_s.append(word[0])

        review_no_integers = [x for x in review_tok if not (x.isdigit()
                                                 or x[0] == '-' and x[1:].isdigit())]
        pattern = '[0-9,_]'
        result_strings_no_int = [re.sub(pattern, '', i) for i in review_no_integers]

        review_stem = [stemmer.stem(word) for word in result_strings_no_int]
        '''
        list_of_lists.append(" ".join(review_tok))
    return list_of_lists

list_of_lists = read_data(files,path)
list_of_lists1 = read_data(files1,path1)

dataset = []

for i in range(0,10):
    dataset.append(list_of_lists[int(len(list_of_lists)*i/10):int(len(list_of_lists)*(i+1)/10)]+list_of_lists1[int(len(list_of_lists)*i/10):int(len(list_of_lists1)*(i+1)/10)])

cv_lr_1 = []; cv_lr_2 = []; cv_lr_3 = []; cv_lr_13 = []; cv_lr_12 = []
cv_SVC_1 = []; cv_SVC_2 = []; cv_SVC_3 = []; cv_SVC_12 = []; cv_SVC_13 = []
tfidf_lr_1 = []; tfidf_lr_2 = []; tfidf_lr_3 = []; tfidf_lr_12 = []; tfidf_lr_13 = []
tfidf_SVC_1 = []; tfidf_SVC_2 = []; tfidf_SVC_3 = []; tfidf_SVC_12 = []; tfidf_SVC_13 = []
cv_nb_1=[]; cv_nb_2=[]; cv_nb_3=[]; cv_nb_12=[]; cv_nb_13=[]
tfidf_nb_1=[]; tfidf_nb_2=[]; tfidf_nb_3=[]; tfidf_nb_12=[]; tfidf_nb_13=[]

for i in range(0,10):
    dataset_test = dataset[i]
    dataset_p = []
    dataset_n = []
    for j in range(0,10):

        if j != i:
            dataset_p.append(dataset[j][0:100])
            dataset_n.append(dataset[j][100:200])
    list_pos = [item for sublist in dataset_p for item in sublist]
    list_neg = [item for sublist in dataset_n for item in sublist]
    dataset_train=list_pos+list_neg

    y_train = [1 if i < 900 else 0 for i in range(1800)]
    y_train1 = [1 if i < 100 else 0 for i in range(200)]

    #varianta 1.1.-count vectorizer unigrame
    cv_1,X,X_test=vec_cv((1,1) ,7, dataset_train,dataset_test)

    #var 1.1.a-Logistic regr
    cv_lr_1.append(clasif_lr(0.1,  X, y_train,  y_train1, X_test))

    #var 1.1.b-linear SVC
    cv_SVC_1.append(classif_SVC(0.35,X,y_train,y_train1,X_test))

    #var 1.1.c-naive bayes
    cv_nb_1.append(classif_NB(X,y_train,X_test,y_train1))

    #varianta 1.2.-Tfidf pe unigrame
    tfidf_1,X,X_test = vec_tdidf((1,1),7, dataset_train,dataset_test)

    #var 1.2.a-cu lr
    tfidf_lr_1.append(clasif_lr(0.8, X, y_train,  y_train1, X_test))

    #var 1.2.b-cu SVC
    tfidf_SVC_1.append(classif_SVC(0.8, X, y_train,  y_train1, X_test))

    #var 1.2.c-NB
    tfidf_nb_1.append(classif_NB(X,y_train,X_test,y_train1))

    # varianta 2-countVectorizer pe bigrame
    cv_2, X, X_test = vec_cv((2, 2), 4,  dataset_train, dataset_test)

    # varianta 2.1.a-cv cu lr pe bigrame
    cv_lr_2.append(clasif_lr(0.35, X, y_train, y_train1, X_test))

    # varianta 2.1.b-cv cu SVC pe bigrame
    cv_SVC_2.append(classif_SVC(0.75, X, y_train,  y_train1, X_test))

    #varianta 2.1.c-cv cu NB pe bigrame
    cv_nb_2.append(classif_NB(X,y_train,X_test,y_train1))

    # varianta 2.2-Tfidf pe bigrame
    tfidf_n, X, X_test = vec_tdidf((2,2), 4,dataset_train,dataset_test)

    # 2.2.a-Tfidf cu LR pe bigrame
    tfidf_lr_2.append(clasif_lr(0.8, X, y_train,  y_train1, X_test))

    # 2.2.b-Tfidf cu SVC pe bigrame
    tfidf_SVC_2.append(classif_SVC(0.2, X, y_train,  y_train1, X_test))

    #2.2.c-Tfidf cu NB pe bigrame
    tfidf_nb_2.append(classif_NB(X,y_train,X_test,y_train1))

    # varianta 3-countVectorizer pe trigrame
    cv_3, X, X_test = vec_cv((3, 3), 1, dataset_train, dataset_test)

    # 3.1.a-cv cu lr pe trigrame
    cv_lr_3.append(clasif_lr(0.85, X, y_train, y_train1, X_test))

    # 3.1.b-cv cu SVC pe trigrame
    cv_SVC_3.append(classif_SVC(0.35, X, y_train,  y_train1, X_test))

    #3.1.c -cv cu NB pe trigrame
    cv_nb_3.append(classif_NB(X,y_train,X_test,y_train1))

    # varianta 3.2-Tfidf pe trigrame
    tfidf_3, X, X_test = vec_tdidf((3, 3), 1,dataset_train,dataset_test)

    # 3.2.a-Tfidf cu LR pe trigrame
    tfidf_lr_3.append(clasif_lr(0.3, X, y_train,  y_train1, X_test))

    # 3.2.b-Tfidf cu SVC pe trigrame
    tfidf_SVC_3.append(classif_SVC(0.1, X, y_train, y_train1, X_test))

    #3.2.c-TFIDF cu NB pe trigrame
    tfidf_nb_3.append(classif_NB(X,y_train,X_test,y_train1))

    # varianta 4.1-countVectorizer pe 1-2 grame
    cv_12, X, X_test = vec_cv((1, 2), 1, dataset_train, dataset_test)

    # varianta 4.1.a-cv cu lr pe unigrame si bigrame
    cv_lr_12.append(clasif_lr(0.3, X, y_train,  y_train1, X_test))

    # varianta 4.1.b-cv cu SVC pe 1-2grame
    cv_SVC_12.append(classif_SVC(0.2, X, y_train,  y_train1, X_test))

    #var 4.1.c- cv cu NB pe 1-2 grame
    cv_nb_12.append(classif_NB(X,y_train,X_test,y_train1))

    # varianta 4.2.a-Tfidf pe 1,2 grame
    tfidf_12, X, X_test = vec_tdidf((1, 2), 1,dataset_train,dataset_test)

    # 4.2.a-Tfidf cu LR pe 1,2 grame
    tfidf_lr_12.append(clasif_lr(0.2,  X, y_train,  y_train1, X_test))

    # 4.2.b-Tfidf cu SVC pe 1,2 grame
    tfidf_SVC_12.append(classif_SVC(0.8, X, y_train, y_train1, X_test))

    #4.2.c-Tfidf cu NB pe 1.2 grame
    tfidf_nb_12.append(classif_NB(X,y_train,X_test,y_train1))

    #varianta 5-countVectorizer pe 1-3 grame (trigrame)
    cv_13,X,X_test = vec_cv((1,3), 1, dataset_train,dataset_test)

    #varianta 5.1.a-cv cu lr pe 1-3 grame
    cv_lr_13.append(clasif_lr(0.3, X, y_train,  y_train1, X_test))

    #varianta 5.1.b-cv cu SVC pe 1-3 grame
    cv_SVC_13.append(classif_SVC(0.1, X, y_train,  y_train1, X_test))

    #5.1.c-cv cu NB pe 1-3 grame
    cv_nb_13.append(classif_NB(X,y_train,X_test,y_train1))

    #varianta 5.2.a-Tfidf pe 1-3 grame
    tfidf_13,X,X_test = vec_tdidf((1,3),1, dataset_train,dataset_test)

    #5.2.a-Tfidf cu LR pe 1-3grame
    tfidf_lr_13.append(clasif_lr(0.8, X, y_train, y_train1, X_test))

    #5.2.b-Tfidf cu SVC pe 1-3 grame
    tfidf_SVC_13.append(classif_SVC(0.8,  X, y_train,  y_train1, X_test))

    #5.2.c-Tfidf cu NB pe 1-3 grame
    tfidf_nb_13.append(classif_NB(X,y_train,X_test,y_train1))
    print("folderul",i,"a fost testat")

print("cv_lr_1 ",sum(cv_lr_1)*10); print("cv_lr_2 ",sum(cv_lr_2)*10);print("cv_lr_3 ",sum(cv_lr_3)*10);print("cv_lr_12 ",sum(cv_lr_12)*10);print("cv_lr_13 ",sum(cv_lr_13)*10)
print("cv_SVC_1 ",sum(cv_SVC_1)*10);print("cv_SVC_2_f ",sum(cv_SVC_2)*10);print("cv_SVC_3 ",sum(cv_SVC_3)*10);print("cv_SVC_12 ",sum(cv_SVC_12)*10);print("cv_SVC_13 ",sum(cv_SVC_13)*10)
print("tfidf_lr_1 ",sum(tfidf_lr_1)*10);print("tfidf_lr_2 ",sum(tfidf_lr_2)*10);print("tfidf_lr_3 ",sum(tfidf_lr_3)*10);print("tfidf_lr_12 ",sum(tfidf_lr_12)*10);print("tfidf_lr_13 ",sum(tfidf_lr_13)*10)
print("tfidf_SVC_1 ",sum(tfidf_SVC_1)*10);print("tfidf_SVC_2 ",sum(tfidf_SVC_2)*10);print("tfidf_SVC_3 ",sum(tfidf_SVC_3)*10);print("tfidf_SVC_12 ",sum(tfidf_SVC_12)*10);print("tfidf_SVC_13 ",sum(tfidf_SVC_13)*10)
print("cv_nb_1",sum(cv_nb_1)*10); print("cv_nb_2 ",sum(cv_nb_2)*10);print("cv_nb_3 ",sum(cv_nb_3)*10);print("cv_nb_12 ",sum(cv_nb_12)*10);print("cv_nb_13 ",sum(cv_nb_13)*10)
print("tfidf_nb_1 ",sum(tfidf_nb_1)*10);print("tfidf_nb_2 ",sum(tfidf_nb_2)*10);print("tfidf_nb_3 ",sum(tfidf_nb_3)*10);print("tfidf_nb_12 ",sum(tfidf_nb_12)*10);print("tfidf_nb_13 ",sum(tfidf_nb_13)*10)


import sqlite3
import re
import helper

class BackEnd:

    def __init__(self):
        self.conn = sqlite3.connect('Students.db')
        self.courses_available = ["BIOLOGY", "COMPUTER SCIENCE", "PHYSICS", "ENGINEERING", "LAW", "ART"]
        self.editable_columns = helper.editable_columns

    def connect(self):
        '''connect to database or creates if not existing'''
        print("Opened student database successfully")
        try:
            cur = self.conn.cursor()
            cur.execute('''
                CREATE TABLE IF NOT EXISTS Students
                (   REG TEXT PRIMARY KEY NOT NULL,
                    FNAME TEXT NOT NULL,
                    LNAME TEXT NOT NULL,
                    AGE INTEGER NOT NULL,
                    EMAIL TEXT,
                    COURSE TEXT,
                    USERNAME TEXT);
            ''')
            self.conn.commit()
            print("Database OPENED successfully")
        except Exception as err:
            print("Error Connecting to database. ERROR : " + str(err))

    def close(self):
        try:
            self.conn.close()
            print("Database CLOSED successfully")

        except Exception as err:
            print("CLOSE FUNCTION ERROR: " + str(err))

    def add(self, reg, fn, ln, age, email, course, user):
        '''function to add new student to database'''
        '''
        Arguments:
        reg: REG_NO text,    email: Email Text
        fn: First Name Text, course: Course Text
        ln: Last Name Text,  user: Username Text
        age: Age Integer
        '''

        email_regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
        course = course.upper()  # convert course input to uppercase

        # REG: error if not string and format Uxxx
        if (not (isinstance(reg, str))):
            print("Invalid REGISTRATION NUMBER. \t(Accepted Format: Uxxx)")
            print("*** Adding Record Failed ***")

            # FIRST NAME: error if not string and not length 2-15
        elif (not (isinstance(fn, str)) or not (len(fn) < 15 and len(fn) > 2)):
            print("Invalid FIRST NAME. \tLength must be 2-15 characters")
            print("*** Adding Record Failed ***")

            # LAST NAME: error if not string and not length 2-15
        elif (not (isinstance(ln, str)) or not (len(ln) < 15 and len(ln) > 2)):
            print("Invalid LAST NAME. \tLength must be 2-15 characters")
            print("*** Adding Record Failed ***")

            # COURSE: error if not string and not in list
        elif (not (isinstance(course, str)) or course not in self.courses_available):
            print("COURSE picked is NOT AVAILABLE. \tRegister with available options : ")
            print(self.courses_available)
            print("*** Adding Record Failed ***")

            # USERNAME: error if not string and not length 2 -15
        elif (not (isinstance(user, str)) or not (len(user) < 15 and len(user) > 2)):
            print("Invalid USERNAME. \tLength must be 2-15 characters")
            print("*** Adding Record Failed ***")

            # EMAIL: error if not string and not correct format
        elif (not re.search(email_regex, email)):
            print("Invalid EMAIL")
            print("*** Adding Record Failed ***")

        else:
            try:
                try:
                    age = int(age)  # converting age to integer
                # AGE: error if not an integer
                except Exception as err:
                    print("Invalid AGE input" + str(err))

                # AGE: error if age is less than 18
                if (18 > age):
                    print("UNDER AGE. \t" + "Student " + str(reg) + " must be an adult to qualify")
                    print("*** Adding Record Failed ***")

                else:
                    cur = self.conn.cursor()
                    cur.execute("INSERT INTO Students Values (?,?,?,?,?,?,?)", (reg, fn, ln, age, email, course, user))
                    self.conn.commit()
                    print("Record successfully added")

            #ERROR if student already exists in database
            except Exception as err:
                print("ERROR: Student "+ str(reg) + " already exists in database")
                print("*** Adding Record Failed ***")

    def display(self):
        '''function to display all student data'''
        try:
            cur = self.conn.cursor()
            cur.execute("SELECT * FROM Students")
            rows = cur.fetchall()
            for row in rows:

                print("REGISTRATION_NUMBER = " + str(row[0]))
                print("NAME = " + str(row[1])+" "+str(row[2]))
                print("AGE = "+ str(row[3]))
                print("EMAIL = "+ str(row[4]))
                print("COURSE = "  + str(row[5]))
                print("USERNAME = " + str(row[6]))
                print("======================================")

        except Exception as err:
            print("DISPLAY ERROR: " + str(err))

    def update(self, reg,targetAttribute,newValue):
        #find data of student with Registration no. = reg, and change the "targetAttribute" to the "newValue"
        self.conn.row_factory = sqlite3.Row
        cur = self.conn.cursor()
        newValue = str(newValue)
        targetAttribute = targetAttribute.upper()

        #CHECK if Reg exists in database
        if reg and reg.strip():
            user_nm = (reg.strip(),)
            query = 'select exists(select 1 from Students where REG=? collate nocase) limit 1'
            # 'query' RETURNS 1 IF REG EXISTS OR 0 IF NOT, AS INTEGER(MAYBE). 'collate nocase'= CASE INSENSITIVE, IT'S OPTIONAL
            check = cur.execute(query, user_nm)
            if check.fetchone()[0] == 0:
                print('Registration_Number NOT found')
                print("*** Update Record Failed ***")
            else:
                print('Registeration_Number found')

                #Conditional operations and validation for targetAttribute
                if (targetAttribute == "FNAME"):
                    # FIRST NAME: error if not length 2-15
                    if (not (isinstance(newValue, str)) or not (len(newValue) < 15 and len(newValue) > 2)):
                        print("Invalid FIRST NAME. \tLength must be 2-15 characters")
                        print("*** Updating Record Failed ***")

                    else: #FIRST NAME Update
                        cur.execute("UPDATE Students set FNAME = ? where REG= ?", (newValue, reg))
                        self.conn.commit()
                        print("*** Update Record Successful ***")

                elif (targetAttribute == "LNAME"):
                    # LAST NAME: error if not length 2-15
                    if (not (isinstance(newValue, str)) or not (len(newValue) < 15 and len(newValue) > 2)):
                        print("Invalid LAST NAME. \tLength must be 2-15 characters")
                        print("*** Updating Record Failed ***")

                    else: #LAST NAME Update
                        cur.execute("UPDATE Students set LNAME = ? where REG= ?", (newValue, reg))
                        self.conn.commit()
                        print("*** Update Record Successful ***")

                elif (targetAttribute == "AGE"):
                    try:
                        newValue = int(newValue)
                    # AGE: error if not an integer
                    except Exception as err:
                        print("Invalid AGE input" + str(err))
                        print("*** Update Record Failed ***")

                    # AGE: error if age is less than 18
                    if (18 > newValue):
                        print("UNDER AGE. \t" + "Student " + str(targetAttribute) + " must be an adult to qualify")
                        print("*** Update Record Failed ***")
                    else: #Age Update
                        cur.execute('UPDATE Students SET AGE=? WHERE REG= ?', (newValue, reg))
                        self.conn.commit()
                        print("*** Update Record Successful ***")

                elif (targetAttribute == "EMAIL"):
                    newValue = str(newValue)
                    email_regex = '^[a-z0-9]+[\._]?[a-z0-9]+[@]\w{2,3}$'

                    # EMAIL: error if not correct format
                    if (not (isinstance(newValue, str))):  # not (or re.search(email_regex,email))):
                        print("Invalid EMAIL")
                        print("*** Update Record Failed ***")

                    else: #EMAIL Update
                        cur.execute('UPDATE Students SET EMAIL=? WHERE REG= ?', (newValue, reg))
                        self.conn.commit()
                        print("*** Update Record Successful ***")

                elif (targetAttribute == "COURSE"):
                    # COURSE: error if not string and not in list
                    if (newValue not in self.courses_available):
                        print("COURSE picked is NOT AVAILABLE. \tRegister with available options : ")
                        print(self.courses_available)
                        print("*** Update Record Failed ***")

                    else: #Course Update
                        cur.execute('UPDATE Students SET COURSE=? WHERE REG= ?', (newValue, reg))
                        self.conn.commit()
                        print("*** Update Record Failed ***")

                elif (targetAttribute == "USER"):
                    #USERNAME: error if not length 2-15
                    if (not (len(newValue) < 15 and len(newValue) > 2)):
                        print("Invalid USERNAME. \tLength must be 2-8 characters")
                        print("*** Update Record Failed ***")

                    else: #USERNAME Update
                        cur.execute('UPDATE Students SET USER=? WHERE REG= ?', (newValue, reg))
                        self.conn.commit()
                        print("*** Update Record Successful ***")

                else:
                    print("Columnn Selected does not exist. \tAvailable columns: " + str(self.editable_columns))
                    print("*** Update Record Failed ***")

        else:
            print('Error')

    def delete(self, reg):
        '''function to delete student from database'''
        try:
            cur = self.conn.cursor()
            cur.execute("DELETE FROM Students WHERE REG=?",(reg,))
            self.conn.commit()
            print("Student "+reg+" deleted")

        except Exception as err:
            print("DELETE FUNCTION ERROR : "+ str(err))


#**************************
# Author : Christian Beasley
# Date   : 5/27/16
#
# Test status: Incomplete
#**************************

from tinysvg.core import SvgObject

def animate(attributeName,from_,to,dur,repeatCount='indefinite',attributeType='XML'):
	return SvgObject.new('animate').addAttrs({
		'attributeType':attributeType,
		'attributeName':attributeName,
		'from':str(from_),
		'to':str(to),
		'dur':str(dur),
		'repeatCount':str(repeatCount)
		})

def animateMotion(path,dur,repeatCount='indefinite'):
	pathID = path.getAttr('id')
	return SvgObject.new('animateMotion').addAttrs({
		'dur':str(dur),
		'repeatCount':str(repeatCount)
		}).addElement(SvgObject.new('mpath').addAttrs({
			'xlink:href':'#'+pathID
			}))

def animateTransform(type_,from_,to,dur,repeatCount='indefinite',attributeName='transform',attributeType='XML'):
	return SvgObject.new('animateTransform').addAttrs({
		'attributeName':attributeName,
		'attributeType':attributeType,
		'type':type_,
		'from':str(from_),
		'to':str(to),
		'dur':str(dur),
		'repeatCount':repeatCount
		})


# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html

# -- Path setup --------------------------------------------------------------

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#

import logging
import os
import sys
sys.path.insert(0, os.path.abspath('.'))

# -- Project information -----------------------------------------------------
_me = 'Jörg Faschingbauer'
_canonical = 'https://www.faschingbauer.me'
project = author = _me
copyright = '2020, '+_me
html_title = _me
html_baseurl = _canonical
release = version = ''

# -- General configuration ---------------------------------------------------
master_doc = 'index'
templates_path = []

# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
    'sphinx.ext.todo',
    'sphinx.ext.viewcode',
    'sphinx.ext.autodoc',
    'sphinx.ext.graphviz',
    'ablog',
    'nbsphinx',
    'sphinxcontrib.fulltoc',
    'sphinxcontrib.programoutput',
    'sphinxcontrib.images',

    'jf.topic',

    'sphinx.environment.collectors.asset',
    'jf.dia',
]
todo_include_todos = True

# ablog
if True:
    import ablog
    templates_path.append(ablog.get_html_templates_path())
    post_date_format = '%Y-%m-%d'

    blog_title = u'Jörg Faschingbauer'
    blog_path = 'blog'

    # a side effect of setting blog_baseurl is that atom.xml feeds
    # are generated altogether
    blog_baseurl = _canonical

    blog_authors = {
        'jfasch': ('Jörg Faschingbauer', _canonical),
    }
    blog_default_author = 'jfasch'

    blog_locations = {
        'daham': ('Graz, Austria', 'https://de.wikipedia.org/wiki/Graz'),
    }
    blog_default_location = 'daham'
    fontawesome_link_cdn = 'https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css'
    blog_feed_fulltext = True
    blog_feed_length = 10
    blog_feed_archives = True

    # feed is http://feeds.feedburner.com/JoergFaschingbauer

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = [
    '_build',
    '**.ipynb_checkpoints',
]
html_context = {}
html_static_path = ['_static']

_BASIC = 'basic'
_RTD = 'sphinx_rtd_theme'
_BETTER = 'better'
_CLOUD = 'cloud'
_PYRAMID = 'pyramid'
_PRESS = 'press'
_NATURE = 'nature'
_ALABASTER = 'alabaster'
_BOOTSTRAP = 'bootstrap'

html_theme = _ALABASTER
html_theme_path = []
html_theme_options = {}

_jf_csss = []

if html_theme == _ALABASTER:
    # RANT: the settings below (page_width 90%, sidebar_width 20% (of
    # page_width, essentially)) result in

    # * div.bodywrapper: margin-left: 20% (=274.75 on my screen)

    # * div.sphinxsidebar: width: 20% (305.267)

    # though the plan is obviously that they have the same calculated
    # size, so the sphinxsidebar fits in bodywrapper's left
    # margin. (sidenote: why the f**k is it done in this way? why not
    # just position clearly with ... whatever ... some flexbox fancy?)

    # however: this *not* the case. for some reason (*), the
    # calculated values are *not* equal, and the sidebar's
    # width=305.267 overlaps into bodywrapper's 274.75 margin-left.

    # (*) hmm ... when I look at the element hierarchy, I see that

    # * div.sphinxsidebar is a child of div.document

    # * div.bodywrapper is a child of div.documentwrapper which is a
    #   child of div.document

    # question: how can it be that bodywrapper'div.s margin-left
    # calculates to a value that appears to be derived from
    # div.document?

    # ANYWAY: stick with it, but keep looking out for better
    # solutions/themes. learn to do web crap better.

    import alabaster

    html_theme_path.append(alabaster.get_path())

    templates_path.append('_templates')

    html_theme_options.update({
        'fixed_sidebar': True,
        'logo': 'logo.png',
        'description': 'Linux und Open Source',
        'page_width': '90%',
        'sidebar_width': '20%',

        # hardwired by default by "basic" theme, to 800px. no idea
        # why. occupy what we can get.
        'body_max_width': '100%',

        # 'github_banner': True,
        # 'github_button': True,

        'font_family': '"Lucida Sans Unicode", "Lucida Grande", sans-serif;'
    })

    html_sidebars = {
        # the more specific match must come first (fortunately
        # dictionary order is preserved since 3.7 :-) prior to that we
        # would have had no chance to fix that other than changing
        # html_sidebars to a list of tuples).
        'blog/**': [
            'about.html',
            'searchbox.html',
            'navigation.html',
            'postcard.html',
        ],
        '**': [
            'about.html',
            'searchbox.html',
            'navigation.html',
        ],
    }

    html_context.update({
        'jf_nav_bg': '#f0f3f8',
        'jf_info_bg': '#fcfcfc',
        'jf_note_bg': '#eee',
    })

    _jf_csss.append('css/jf-alabaster.css')

if html_theme == _RTD:
    # nav and location feedback really great

    # looks good on mobile

    # on wider screen a lot of screen real estate to the right is wasted

    # html_sidebars disregarded

    # RTD css unreadable (uglified?)

    extensions.append('sphinx_rtd_theme')

    html_theme_options['collapse_navigation'] = False
    html_theme_options['navigation_depth'] = -1

    # context that jinja (and rst, via the rstjinja extension) sees.
    html_context.update({
        # experimental: this is how we can get settings into templates
        'READTHEDOCS': False, # {en,dis}able versions.html
        'versions': [('blah', 'https://www.google.com'),],

        # reading the RTD theme sources, I see that this is the RTD way of
        # adding my own css.
        'extra_css_files': ['_static/css/jf.css'],
    })

if html_theme == _BETTER:
    from better import better_theme_path
    html_theme_path = [better_theme_path]

if html_theme == _CLOUD:
    html_theme_options['max_width'] = '100%'
    pass

if html_theme == _PYRAMID:
    import pyramid_sphinx_themes
    html_theme_path += pyramid_sphinx_themes.get_html_themes_path()

if html_theme == _PRESS:
    # html_sidebars as set above won't work. emptying it does,
    # somehow.

    # nav is buggy.
    pass

if html_theme == _NATURE:
    pass

if html_theme == _BASIC:
    pass

if html_theme == _BOOTSTRAP:
    # just a try, no navigation with location feedback

    import sphinx_bootstrap_theme
    html_theme_path += sphinx_bootstrap_theme.get_html_theme_path()

def rstjinja(app, docname, source):
    """Render our pages as a jinja template for fancy templating goodness.

    Eroc Holscher mentions this somewhere in his blog.

    """
    # Make sure we're outputting HTML
    if app.builder.format != 'html':
        return
    src = source[0]
    rendered = app.builder.templates.render_string(
        src, app.config.html_context
    )
    source[0] = rendered

def setup(app):
    for css in _jf_csss:
        app.add_css_file(css)

    app.connect("source-read", rstjinja)

    # html_sidebars has two matches, and both match any /blog/
    # docname. the first match is more specific than the second, which
    # I consider a common case. nevertheless sphinx generates a
    # warning. filter that out.

    # (rant) I have no idea what's the benefit of wrapping loggers
    # into LoggerAdapter's. Or what SphinxLoggerAdapter's purpose
    # is. Fortunately the LoggerAdapter (victim.logger) is friendly
    # enough to have a 'logger' member. gosh; I only want to silence a
    # warning.
    class NoWarnMultipleMatches(logging.Filter):
        def filter(self, record):
            return 'matches two patterns in html_sidebars' not in record.getMessage()
    import sphinx.builders.html as victim
    victim.logger.logger.addFilter(NoWarnMultipleMatches())


from plsr import plsr_numba,predict_numba
import numpy as np

X = np.array([[0., 0., 1.], [1.,0.,0.], [2.,2.,2.], [2.,5.,4.]])
Y = np.array([[0.1, -0.2], [0.9, 1.1], [6.2, 5.9], [11.9, 12.3]])
rows=len(X)
colsX=len(X[0])
colsY=len(Y[0])
factors=2
T=np.zeros((rows,factors))
U=np.zeros((rows,factors))
P=np.zeros((colsX,factors))
Q=np.zeros((colsY,factors))
W=np.zeros((colsX,colsX))
B=np.zeros((colsX))
Y_=np.zeros((rows,colsY))
plsr_numba(X,Y,factors,1e-7,T,U,P,Q,W,B)
print(predict_numba(W,Q,P,X,Y_,B,factors))


from ..charting.bar import Bar
from ..charting import eval
from ..events import events
from strategy import Strategy

class SDZone(Strategy):
    events = [events.EVENT_BAR, events.EVENT_VERT, events.EVENT_TERMINATE]
    BARS = 'bars'
    VERT_SCRATCH_H = 'vertices_high'
    VERT_SCRATCH_L = 'vertices_low'
    VERT_H         = 'rl_high'
    VERT_L         = 'rl_low'
    HIGH           = 'high'
    LOW            = 'low'

    def __init__(self, receiver):
        ''' Initialize strategy with receiver '''
        super(SDZone, self).__init__(receiver)
        self.charts = {}

    def get_chart_key(self, symbol, tf):
        key = '' + symbol + tf
        return key

    def init_chart(self, chart):
        chart[SDZone.BARS] = []
        chart[SDZone.VERT_SCRATCH_H] = []
        chart[SDZone.VERT_SCRATCH_L] = []
        chart[SDZone.VERT_H] = []
        chart[SDZone.VERT_L] = []
        chart[SDZone.HIGH] = 0.
        chart[SDZone.LOW] = 0.

    def handle_bar(self, bar, symbol, tf):
        pass
        # Creating order for testing

    def handle_vert(self, bar, symbol, tf, is_high, idx):
        # Creating order for testing
        if eval.is_candlestick(bar):
            if is_high:
                # High vert, short entry
                entry = max(bar.open, bar.close)
                sl = (bar.high + .0005)
                tp = entry - (sl - entry) * 3

                order = events.OrderEvent(symbol, entry, sl, tp, False)
            else:
                # Low vert, long entry
                entry = min(bar.open, bar.close)
                sl = (bar.high - .0005)
                tp = entry + (entry - sl) * 3

                order = events.OrderEvent(symbol, entry, sl, tp, True)

            self._receiver.handle_event(order)

    def handle_event(self, event):
        ''' Receive the market data - if still trying, add to set.
        If we have completed training, evaluate data received
        '''
        if event.type == events.EVENT_BAR:
            self.handle_bar(event.bar, event.symbol, event.tf)
        elif event.type == events.EVENT_VERT:
            self.handle_vert(event.bar, event.symbol, event.tf, event.is_high, event.idx)


import numpy as np
import sys
import datetime

def sysArgParse(filename=False):
    # Parsing System Arguments for running heuristics
    sysArguments = sys.argv
    strBoolHeuristic1 = (sys.argv[1]).split('=')[-1]
    strBoolHeuristic2 = (sys.argv[2]).split('=')[-1]
    heuristic1Bool = False
    heuristic2Bool = False

    if strBoolHeuristic1 in ['True','true','1']:
        heuristic1Bool = True
    if strBoolHeuristic2 in ['True','true','1']:
        heuristic2Bool = True

    if filename == False:
        return heuristic1Bool , heuristic2Bool
    else:
        return heuristic1Bool , heuristic2Bool, str.rstrip(sys.argv[3])

def writeOutputDimacs(filename,assignments):

    f = open("./" + filename + ".out","w+")
    if len(assignments) != 0:

        f.write("p cnf " + str(len(assignments)) + " " + str(len(assignments)) +"\n")
        for literal in assignments:

            # Setting all unassigned to true
            if assignments[literal] == -1:
                assignments[literal] = 1

            if assignments[literal] == 0:
                f.write("-")
            f.write(str(literal) + " 0\n" )

    f.close()
def appendSplitCountToFile(splitCountList,heuristic1Bool,heuristic2Bool,seed=-1):

    currentTimeStamp = str(datetime.datetime.now())
    f= open("./output_files/splitCountsLog.txt","a+")
    f.write("Heuristic 1  = " + str(heuristic1Bool) + "------" + "Heuristic 2  = " + str(heuristic2Bool) +
        "-----------" + currentTimeStamp + "-----------seed = " + str(seed) + "\n\n" )
    f.write(str(splitCountList) + "\n\n\n\n")
    f.close()

def return_var_and_negated_var(variable):

    #Helper function to return variable and it's negation
    if(variable[0] == '-'):
        return variable , variable[1:]
    else:
        return variable , '-' + variable
def determineNonEmptyClauses(c2vDict):
    count = 0
    for clause in c2vDict:
        if len(c2vDict[clause])!=0:
            count += 1

    return count
def printSudokuGrid(assignments):

    #Helper function to visualize solved soduko
    M = np.zeros([9,9])
    for l in assignments:
      if assignments[l] == 1:
          i = int(l[0])-1
          j = int(l[1]) - 1
          v = int(l[2])
          M[i][j]= v

    for i in range(9):
      for j in range(9):
          print(str(M[i][j]) + " ", end = '')
      print("")

def read_dimacs_format(filepath):

    #Function for parsing DIMACS format
    #Returns lines as lists of lists
    #Each list is a line
    with open(filepath) as filePointer:
        dimacs_file_content = filePointer.readlines()

    return dimacs_file_content

def parseTestSudokus(filename):

    with open(filename) as filePointer:
        file_content = filePointer.readlines()

    dimacs_sudoku_test_set = []
    for sudoku in file_content:

        sudoku = str.rstrip(sudoku)
        dimacs_sudoku = []
        for idx,character in enumerate(sudoku) :
            if character == '.':
                continue
            else:
                row = int(idx/9) + 1
                col = int(idx % 9) + 1

                dimacs_string = str(row) + str(col) + character + " " + str(0)
                dimacs_sudoku.append(dimacs_string)

        if len(dimacs_sudoku)!=0:
            dimacs_sudoku_test_set.append(dimacs_sudoku)

    return dimacs_sudoku_test_set

def simplifyTautologyAndPrepareDataStructures(rules_file_content):

    # This function needs to be executed oncly once.
    # Because tautology once simplified / removed , will not occur again.
    # This function also intialises all data structures.

    c2vDict = {} # Data Structure to map clause Ids with variables
    v2cDict = {} # Data Structure to map variables with clause Ids
    countVarDict = {} # Data Strucutre to maintain a count of all seen varibles (positive or negative)
    assignments = {} # Data Structure which contains status of current assignments to literals , -1 = Unknown , 1 = True , 0  = False

    #Read all lines
    #Ignore the ones which begin with 'p' or 'c'
    #Check if clause contains tautology
    #Ignore tautology clauses
    #Assign initial values to c2vDict , v2cDict , countVarDict , assignments
    for index,line in enumerate(rules_file_content):
        line = str.rstrip(line)
        if line[0] in ['p','c']:
            continue
        else:
            clause = line
            clause = clause.split(' ')
            clause = clause[:-1] # Getting rid of the 0 at the end
            clause = [s for s in clause if s != ''] # Removing additional spaces

            tautologyFlag = False
            dummyDict = {} # Temporary Dict for each clause to remove tautology and duplicates
            for variable in clause:

                if variable in dummyDict: # Checking for Duplicates
                    continue
                variable , negatedVariable = return_var_and_negated_var(variable)

                if negatedVariable in dummyDict:
                    tautologyFlag = True

                if variable not in dummyDict :
                    dummyDict[variable] = True

                #Need to add literal to assignment list over here
                if variable[0]=='-':
                    if negatedVariable not in assignments:
                        assignments[negatedVariable] = -1
                else:
                    if variable not in assignments:
                        assignments[variable] = -1

            if tautologyFlag == False: # The clause is not a tautology

                c2vDict[index] = clause

                for variable in clause:

                    if variable not in v2cDict:

                        v2cDict[variable] = []
                        countVarDict[variable] = 0

                    v2cDict[variable].append(index)
                    countVarDict[variable] += 1

    return c2vDict , v2cDict , countVarDict, assignments


if __name__ == '__main__':
    import argparse
    import json
    import numpy as np
    import json
    import os
    import json
    import pandas as pd
    import spacy

    from spacy.tokenizer import Tokenizer
    from spacy.lang.en import English

    nlp = English()
    tokenizer = Tokenizer(nlp.vocab)

    parser = argparse.ArgumentParser()
    parser.add_argument('--data-path', action='store')
    parser.add_argument('--concept-path', action='store')
    args = parser.parse_args()

    if not os.path.exists(os.path.dirname(args.concept_path)):
        os.makedirs(os.path.dirname(args.concept_path))

    with open(args.data_path) as f:
        data = [json.loads(line) for line in f if line.strip() if line.strip()]

    pretok = lambda sen: sen[:-1] if sen[-1] == "." else sen
    preproc = lambda sen: set([str(w) for w in tokenizer(pretok(sen).lower())])
    preproc_sw = lambda sen: set([str(w) for w in sen if nlp.vocab[w].is_stop == False])

    def is_overlap(p, h):
        prem_tokens = preproc_sw(preproc(p))
        hyp_tokens = preproc_sw(preproc(h))
        overlap = hyp_tokens.intersection(prem_tokens)
        if len(prem_tokens) == 0 and len(hyp_tokens) == 0:
            return 1, True, True
        frac = len(overlap) / len(hyp_tokens) if hyp_tokens else len(overlap) / len(prem_tokens)

        return frac, len(overlap) == len(hyp_tokens), len(overlap) == len(prem_tokens)

    for i, ex in enumerate(data):
        frac, ovh, ovp = is_overlap(ex['sentence1'], ex['sentence2'])
        data[i]['overlap_full_h'] = ovh

    concept = np.array([1 if e['overlap_full_h'] else 0 for e in data], dtype=int)

    np.save(args.concept_path, concept)