import json

def get_client(secrets_path):
    'Returns an OAuth client, using the given path as a secrets store'
    # Find you
    API_KEY = '<Your API Key, AKA Client ID>@AMER.OAUTHAP'
    REDIRECT_URI = '<Your Redirect URI>'

    import os
    import pickle
    from requests_oauthlib import OAuth2Session

    # Load old token from secrets directory
    token_path = os.path.join(os.path.expanduser(secrets_path), 'token.json')
    token = None
    try:
        with open(token_path, 'rb') as f:
            token = pickle.load(f)
            print(token)
    except FileNotFoundError:
        pass

    # On failure, fetch a new token using OAuth and Selenium. Unfortunately TD
    # only supports the webapp workflow, so we have to open up a browser.
    if token is None:
        from selenium import webdriver
        from selenium.webdriver.chrome.options import Options

        oauth = OAuth2Session(API_KEY, redirect_uri=REDIRECT_URI)
        authorization_url, state = oauth.authorization_url(
            'https://auth.tdameritrade.com/auth')

        # Open a Chrome browser to take the credentials
        chrome_options = Options()
        user_data_dir = os.path.join(secrets_path, 'chrome')
        chrome_options.add_argument("user-data-dir={}".format(user_data_dir))
        with webdriver.Chrome(options=chrome_options) as driver:
            driver.get(authorization_url)

            # Wait to catch the redirect
            import time
            callback_url = ''
            while not callback_url.startswith(REDIRECT_URI):
                callback_url = driver.current_url
                time.sleep(1)

            token = oauth.fetch_token(
                'https://api.tdameritrade.com/v1/oauth2/token',
                authorization_response=callback_url,
                access_type='offline',
                client_id=API_KEY,
                include_client_id=True)

    # Record the token
    def update_token(t):
        with open(token_path, 'wb') as f:
            pickle.dump(t, f)
    update_token(token)

    # Return a new session configured to refresh credentials
    return OAuth2Session(API_KEY, token=token,
                         auto_refresh_url='https://api.tdameritrade.com/v1/oauth2/token',
                         auto_refresh_kwargs={'client_id': API_KEY},
                         token_updater=update_token)

client = get_client(secrets_path)
resp = client.get(
    'https://api.tdameritrade.com/v1/marketdata/quotes',
    params={'apikey': API_KEY, 'symbol': 'AAPL'})
resp = resp.json()


import config
from sqlalchemy import Column, BigInteger, String, ForeignKey, Table
from sqlalchemy.orm import relationship, backref
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class WhitelistEntry(Base):
	__tablename__ = 'whitelist_entries'
	userId = Column(BigInteger, primary_key=True)
	guildId = Column(BigInteger, primary_key=True)
	wallet = Column(String)

engine = create_engine(config.db_path, echo=False, future=True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)

def save_entry(session: Session, user_id: int, wallet: str, guild_id: int):
	r = get_entry(session, user_id, guild_id)
	if r is not None:
		r.wallet = wallet
		session.add(r)
	else:
		e = WhitelistEntry(userId=user_id, guildId=guild_id, wallet=wallet)
		session.add(e)
	session.commit()

def delete_entry(session: Session, user_id: int, guild_id: int) -> bool:
	r = get_entry(session, user_id, guild_id)
	if r is not None:
		session.delete(r)
		session.commit()
		return True
	return False

def get_entries(session: Session, guild_id: int):
	return session \
		.query(WhitelistEntry) \
		.filter(WhitelistEntry.guildId == guild_id) \
		.all()

def get_entry(session: Session, user_id: int, guild_id: int):
	return session \
		.query(WhitelistEntry) \
		.filter(WhitelistEntry.userId == user_id and WhitelistEntry.guildId == guild_id) \
		.first()

class Whitelist(object):
	@staticmethod
	def add(user_id: int, wallet: str, guild_id: int) -> bool:
		with Session() as session:
			save_entry(session, user_id, wallet, guild_id)
			return True
		return False

	@staticmethod
	def remove(user_id: int, guild_id: int) -> bool:
		with Session() as session:
			return delete_entry(session, user_id, guild_id)
		return False

	@staticmethod
	def check(user_id: int, guild_id: int) -> str:
		with Session() as session:
			entry = get_entry(session, user_id, guild_id)
			if entry is not None:
				return entry.wallet

	@staticmethod
	def count(guild_id: int) -> int:
		with Session() as session:
			return len(get_entries(session, guild_id))
		return 0


"""
BINocular backend for beamline ID03:EH2
This backend should serve as a basic example of a backend based on
xrayutilities [1]. It still uses PyMCA for parsing the spec,edf files.
The 'original' ID03 backend was used as a template.

Created on 2014-10-16

[1] http://xrayutilities.sourceforge.net/

author: Dominik Kriegner (dominik.kriegner@gmail.com)
"""

import sys
import os
import glob
import numpy

import xrayutilities as xu
from PyMca import specfile

#python3 support
PY3 = sys.version_info > (3,)
if PY3:
    pass
else:
    from itertools import izip as zip

try:
    from PyMca import specfilewrapper, EdfFile
except ImportError:
    from PyMca.PyMcaIO import specfilewrapper, EdfFile

from .. import backend, errors, util

class HKLProjection(backend.ProjectionBase):
    # scalars: mu, theta, [chi, phi, "omitted"] delta, gamR, gamT, ty, wavelength
    # 3x3 matrix: UB
    def project(self, mu, theta, delta, gamR, gamT, ty, wavelength, UB, qconv):
        qconv.wavelength = wavelength
        h, k, l = qconv.area(mu, theta,
                             mu, delta, ty, gamT, gamR,
                             UB=UB.reshape((3,3)))
        return (h, k, l)

    def get_axis_labels(self):
        return 'H', 'K', 'L'

class HKProjection(HKLProjection):
    def project(self, mu, theta, delta, gamR, gamT, ty, wavelength, UB, qconv):
        H, K, L = super(HKProjection, self).project(mu, theta, delta, gamR, gamT, ty, wavelength, UB, qconv)
        return (H, K)

    def get_axis_labels(self):
        return 'H', 'K'

class QProjection(backend.ProjectionBase):
    def project(self, mu, theta, delta, gamR, gamT, ty, wavelength, UB, qconv):
        qconv.wavelength = wavelength
        qx, qy, qz = qconv.area(mu, theta,
                                mu, delta, ty, gamT, gamR,
                                UB=numpy.identity(3))
        return (qx, qy, qz)

    def get_axis_labels(self):
        return 'qx', 'qy', 'qz'

class ID03Input(backend.InputBase):
    # OFFICIAL API
    def generate_jobs(self, command):
        scans = util.parse_multi_range(','.join(command).replace(' ', ','))
        if not len(scans):
            sys.stderr.write('error: no scans selected, nothing to do\n')
        for scanno in scans:
            scan = self.get_scan(scanno)
            try:
                pointcount = scan.lines()
            except specfile.error: # no points
                continue
            next(self.get_images(scan, 0, pointcount-1, dry_run=True))# dryrun

            if self.config.target_weight and pointcount > self.config.target_weight * 1.4:
                for s in util.chunk_slicer(pointcount, self.config.target_weight):
                    yield backend.Job(scan=scanno, firstpoint=s.start, lastpoint=s.stop-1, weight=s.stop-s.start)
            else:
                yield backend.Job(scan=scanno, firstpoint=0, lastpoint=pointcount-1, weight=pointcount)

    def process_job(self, job):
        super(ID03Input, self).process_job(job)
        scan = self.get_scan(job.scan)

        scanparams = self.get_scan_params(scan) # wavelength, UB
        pointparams = self.get_point_params(scan, job.firstpoint, job.lastpoint) # 1D array of diffractometer angles + mon + transm
        images = self.get_images(scan, job.firstpoint, job.lastpoint) # iterator!

        for pp, image in zip(pointparams, images):
            yield self.process_image(scanparams, pp, image)

    def parse_config(self, config):
        super(ID03Input, self).parse_config(config)
        self.config.xmask = util.parse_multi_range(config.pop('xmask'))
        self.config.ymask = util.parse_multi_range(config.pop('ymask'))
        self.config.specfile = config.pop('specfile')
        self.config.imagefolder = config.pop('imagefolder', None)
        self.config.UB = config.pop('ub', None)
        if self.config.UB:
            self.config.UB = util.parse_tuple(self.config.UB, length=9, type=float)
        self.config.sdd = float(config.pop('sdd'))
        self.config.pixelsize = util.parse_tuple(config.pop('pixelsize'), length=2, type=float)
        self.config.centralpixel = util.parse_tuple(config.pop('centralpixel'), length=2, type=int)

    def get_destination_options(self, command):
        if not command:
            return False
        command = ','.join(command).replace(' ', ',')
        scans = util.parse_multi_range(command)
        return dict(first=min(scans), last=max(scans), range=','.join(command))

    # CONVENIENCE FUNCTIONS
    _spec = None
    def get_scan(self, scannumber):
        if self._spec is None:
            self._spec = specfilewrapper.Specfile(self.config.specfile)
        return self._spec.select('{0}.1'.format(scannumber))

    def find_edfs(self, pattern, scanno):
        files = glob.glob(pattern)
        ret = {}
        for file in files:
            try:
                filename = os.path.basename(file).split('.')[0]
                scan, point, image = filename.split('_')[-3:]
                scan, point, image = int(scan), int(point), int(image)
                if scan == scanno and point not in list(ret.keys()):
                    ret[point] = file
            except ValueError:
                continue
        return ret

    @staticmethod
    def apply_mask(data, xmask, ymask):
        roi = data[ymask, :]
        return roi[:, xmask]

    # MAIN LOGIC
    def get_scan_params(self, scan):
        UB = numpy.array(scan.header('G')[2].split(' ')[-9:],dtype=numpy.float)
        wavelength = float(scan.header('G')[1].split(' ')[-1])

        return wavelength, UB

    def get_images(self, scan, first, last, dry_run=False):
        try:
            uccdtagline = scan.header('UCCD')[0]
            UCCD = os.path.split(os.path.dirname(uccdtagline.split()[-1]))
        except:
            print('warning: UCCD tag not found, use imagefolder for proper file specification')
            UCCD = []
        pattern = self._get_pattern(UCCD)
        matches = self.find_edfs(pattern, scan.number())
        if set(range(first, last + 1)) > set(matches.keys()):
            raise errors.FileError("incorrect number of matches for scan {0} using pattern {1}".format(scan.number(), pattern))
        if dry_run:
            yield
        else:
            for i in range(first, last+1):
                edf = EdfFile.EdfFile(matches[i])
                yield edf.GetData(0)

    def _get_pattern(self,UCCD):
       imagefolder = self.config.imagefolder
       if imagefolder:
           try:
               imagefolder = imagefolder.format(UCCD=UCCD, rUCCD=list(reversed(UCCD)))
           except Exception as e:
               raise errors.ConfigError("invalid 'imagefolder' specification '{0}': {1}".format(self.config.imagefolder, e))
       else:
           imagefolder = os.path.join(*UCCD)

       if not os.path.exists(imagefolder):
           raise ValueError("invalid 'imagefolder' specification '{0}'. Path {1} does not exist".format(self.config.imagefolder, imagefolder))
       return os.path.join(imagefolder, '*')

class EH2(ID03Input):
    monitor_counter = 'Monitor'
    # define ID03 goniometer, SIXC geometry with 2D detector mounted on a
    # translation-axis (distance changing with changing Gamma)
    # The geometry is: 1+3S+2D
    # sample axis mu, th, chi, phi -> here chi,phi are omitted
    # detector axis mu, del, gam
    # gam is realized by a translation along z (gamT) and rotation around x+ (gamR)
    qconv = xu.experiment.QConversion(['x+', 'z-'],  # 'y+', 'z+'
                                      ['x+', 'z-', 'ty', 'tz', 'x+'],
                                      [0, 1, 0])
    # convention for coordinate system: y downstream; z outwards; x upwards
    # (righthanded)
    # QConversion will set up the goniometer geometry. So the first argument
    # describes the sample rotations, the second the detector rotations and the
    # third the primary beam direction.
    ty = 600. # mm

    def parse_config(self, config):
        super(EH2, self).parse_config(config)
        centralpixel = self.config.centralpixel # (row, column) = (gamma, delta)
        # define detector parameters
        roi = (self.config.ymask[0], self.config.ymask[-1]+1,
               self.config.xmask[0], self.config.xmask[-1]+1)
        self.qconv.init_area('x+', 'z-',
                             cch1=centralpixel[1], cch2=centralpixel[0],
                             Nch1=516, Nch2=516,
                             pwidth1=self.config.pixelsize[1],
                             pwidth2=self.config.pixelsize[0],
                             distance=self.config.sdd-self.ty,
                             roi=roi)
        # distance sdd-600 corresponds to distance of the detector chip from
        # the gamR rotation axis (rest is handled by the translations ty and
        # gamT (along z))
        print(('{:>9} {:>10} {:>9} {:>9}'.format('Mu', 'Theta', 'Delta', 'Gamma')))

    def process_image(self, scanparams, pointparams, image):
        mu, theta, chi, phi, delta, gamma, mon, transm = pointparams
        wavelength, UB = scanparams
        data = image / mon / transm
        print(('{:9.4f} {:10.4f} {:9.4f} {:9.4f}'.format(mu, theta, delta, gamma)))

        # recalculate detector translation (which should be saved!)
        gamT = self.ty * numpy.tan(numpy.radians(gamma))

        # masking
        intensity = self.apply_mask(data, self.config.xmask, self.config.ymask)

        # no polarization correction for the moment!

        return intensity, numpy.ones_like(intensity), (mu, theta, delta, gamma, gamT,#weights added to API. keeps functionality identical with wights of one
                           self.ty, wavelength, UB, self.qconv)

    def get_point_params(self, scan, first, last):
        sl = slice(first, last+1)

        MU, TH, CHI, PHI, DEL, GAM, MON, TRANSM = list(range(8))
        params = numpy.zeros((last - first + 1, 8))
        # Mu, Theta, Chi, Phi, Delta, Gamma, MON, transm
        params[:, CHI] = scan.motorpos('Chi')
        params[:, PHI] = scan.motorpos('Phi')
        params[:, TH] = scan.datacol('thcnt')[sl]
        params[:, GAM] = scan.datacol('gamcnt')[sl]
        params[:, DEL] = scan.datacol('delcnt')[sl]
        params[:, MON] = scan.datacol(self.monitor_counter)[sl]
        params[:, TRANSM] = scan.datacol('transm')[sl]
        params[:, MU] = scan.datacol('mucnt')[sl]
        return params


import sys
import importlib

def run_test(module):
    for k, v in module.__dict__.items():
        if k[:4] == 'test' and hasattr(v, '__call__'):
            v()

if __name__ == '__main__':
    n = sys.argv[1]
    m = importlib.import_module(n)
    run_test(m)


import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(1,24, 24)
y = x

plt.plot(x,y)
plt.xticks(np.linspace(1,24, 24))
plt.yticks(np.linspace(1,24,24),[r'$\alpha$',r'$\beta$',r'$\gamma$',r'$\delta$',r'$\epsilon$',r'$\zeta$',r'$\eta$',r'$\theta$',r'$\iota$',r'$\kappa$',r'$\lambda$',r'$\mu$',r'$\nu$',r'$\xi$',r'$omicron$',r'$\pi$',r'$\rho$',r'$\sigma$',r'$\tau$',r'$\upsilon$',r'$\phi$',r'$\chi$',r'$\psi$',r'$\omega$']),
plt.legend('greek alphabet')
plt.show()


import pprint, bson

from classes.collection import Collection

from classes.helpers.functions import (
    presentChoiceString,
    presentChoice,
    handleBool,
    waitForInput
)

class SkillCategory(Collection):

    def __init__(self, name, workName, database):
        super().__init__(name, workName, database)

    def insertDocument(self):
        skillList = []

        print("\n* ADDING A NEW SKILL CATEGORY:")
        print(" * name:")
        name = presentChoiceString()
        print(" * name (Portuguese):")
        name_pt = presentChoiceString()
        print(" * icon:")
        icon = presentChoiceString()
        print(" * Add skills? (Y/N)")
        choice = handleBool()
        while choice:
            newSkill = {"_id" : bson.ObjectId(), "name" : "", "proficiency" : 0, "icon" : ""}

            print(" * skill name:")
            newSkill["name"] = presentChoiceString()
            print(" * skill proficiency (1 to 3):")
            newSkill["proficiency"] = presentChoice()
            print(" * skill icon:")
            newSkill["icon"] = presentChoiceString()

            skillList.append(newSkill)
            print(" * Add another skill? (Y/N)")
            choice = handleBool()

        newSkillCategory = {
            "name" : name,
            "name_pt" : name_pt,
            "icon" : icon,
            "skillList" : skillList
        }
        self.database[self.workName].insert_one(newSkillCategory)
        print("\n* NEW SKILL CATEGORY ADDED!")

    def modifyDocument(self):
        document = self.findDocument()

        if document == None:
            return

        print("\n* MODIFYING A SKILL CATEGORY:")
        for key in list(document.keys()):
            if (key != "_id" and key != "__v" and key != "skillList"):
                print("* Change '{}' field? (Y/N)".format(key))
                choice = handleBool()
                if choice:
                    print("* New '{}':".format(key))
                    value = presentChoiceString()

                    self.database[self.workName].find_one_and_update(
                        { "_id" : document["_id"] },
                        { '$set' : { key : value } }
                    )
            elif key == "skillList":
                newList = document[key]
                pprint.pprint(newList)
                print("\n* Change '{}'? (Y/N)".format(key))
                choice = handleBool()
                while choice:
                    print("Add a new skill to this list? (Y/N)")
                    newSkillChoice = handleBool()
                    if newSkillChoice:
                        newSkill = { "_id" : bson.ObjectId(), "name" : "", "proficiency" : 0, "icon" : ""}

                        print(" * skill name:")
                        newSkill["name"] = presentChoiceString()
                        print(" * skill proficiency (1 to 3):")
                        newSkill["proficiency"] = presentChoice()
                        print(" * skill icon:")
                        newSkill["icon"] = presentChoiceString()
                        newList.append(newSkill)

                        self.database[self.workName].find_one_and_update(
                            { "_id" : document["_id"] },
                            { '$set' : { key : newList } }
                        )

                    print("Modify this list? (Y/N)")
                    modifySkillChoice = handleBool()
                    if modifySkillChoice:
                        newSkill = { "_id" : "", "name" : "", "proficiency" : 0, "icon" : ""}
                        print(" * Which index to modify? (Starts at 1)")
                        index = presentChoice()

                        newSkill["_id"] = newList[index - 1]["_id"]
                        print(" * skill name:")
                        newSkill["name"] = presentChoiceString()
                        print(" * skill proficiency (1 to 3):")
                        newSkill["proficiency"] = presentChoice()
                        print(" * skill icon:")
                        newSkill["icon"] = presentChoiceString()
                        newList[index - 1] = newSkill

                        self.database[self.workName].find_one_and_update(
                            { "_id" : document["_id"] },
                            { '$set' : { key : newList } }
                        )

                    print("Remove a skill from this list? (Y/N)")
                    removeSkillChoice = handleBool()
                    if removeSkillChoice:
                        print(" * Which index to remove? (Starts at 1)")
                        index = presentChoice()
                        newList.pop(index - 1)

                        self.database[self.workName].find_one_and_update(
                            { "_id" : document["_id"] },
                            { '$set' : { key : newList } }
                        )

                    if (not newSkillChoice and not removeSkillChoice):
                        choice = False
        print("\n* DOCUMENT UPDATED!")
        waitForInput(True)


#标注训练集的anchor
"""
在训练集中，将每个anchor作为一个训练样本，为了训练目标检测模型，需要为每个anchor标注两类标签：
1.anchor所含目标的类别，简称类别
2.真实边界框ground truth相对anchor的偏移量，偏移量offset,

在目标检测时，
1.首先生成多个anchor,
2.然后为每个anchor预测类别以及偏移量，
3.接着根据预测的偏移量调整anchor位置从而得到预测边界框，
4.最终筛选需要输出的预测边界框

在目标检测的训练集中，每个图像已经标注了真实边界框ground truth的位置以及所含目标的类别；
在生成anchor之后，主要依据与anchor相似的真实边界框ground truth的位置和类别信息为anchor标注，
问题：该如何为anchor分配与其相似的真实边界框ground truth呢

假设图像中的anchor分别为A1，A2,...,Ana；真实边界框ground truth分别为B1,B2,...,Bnb,且na>=nb(即anchor的数量大于ground truth的数量)
定义矩阵X属于R-na*nb,其中第i行第j列的元素xij为anchor Ai与ground-truth Bj 的IOU
1.首先，找出矩阵X中最大元素，并将该元素的行索引和列索引分别记为i1,j1
为anchor Ai1分配ground-truth Bj1; 显然，anchor Ai1 和ground-truth Bj1 在所有'anchor and ground-truth'中相似度最高
2.接下来，将矩阵X中第i1行和第j1列上所有的元素丢弃，(我觉得这里是因为Bj1和Ai1互为最佳匹配，因此不需要再进行选择)
找出矩阵X中剩余的最大元素，并将该元素的行索引和列索引分别记为i2,j2，
为anchor Ai2分配ground-turth Bj2 再讲矩阵中第i2行和第j2列所有元素丢弃
3.此时矩阵X中已有两行、两列元素被丢弃，
以此类推，知道矩阵X中所有nb列元素全部被丢弃，(因为一般anchor的数量大于ground-truth)
这个时候，已经为nb个anchor各分配了一个 ground-truth,
4.接下来，只需要遍历剩余的na-nb个anchor：
给定其中的anchor Ai ,根据矩阵X的第i行找到与Ai IOU最大的ground-truth Bj(值得注意的是，这里X和Bj用的应该是未丢弃元素之前的矩阵和元素),
且只有当该IOU大于预先设定的阈值时，才为anchor Ai分配真实边界框Bj

现在可以标注anchor的类别class和偏移量offset
如果一个anchor A 被分配了ground-truth B，将anchor A的类别设为B的类别，并根据B和A的中心坐标的相对位置以及两个框的相对大小为anchor A标注偏移量
有数据集中各个框的位置和大小各异，因此这些相对位置和相对大小通常需要一些特殊变换，才能使偏移量的分布更加均匀，从而更容易拟合
设anchor A及其分配的ground-truth B的中心坐标分别为(xa,ya)和(xb,yb); A 和 B的宽分别为wa和wb; 高分别为ha和hb； 一个常用的技巧是将A的偏移量标注为：
公式见文档，其中常数的默认值为 (mu)_x=(mu)_y=(mu)_w=(mu)_h=0, (sigma)_x=(sigma)_y=0.1, (sigma)_w=(sigma)_h=0.2
如果一个anchor没有被分配真实边界框ground-truth ,那么只需要将该anchor的类别设为背景，类别为背景的anchor通常被称为父类anchor,其余被称为正类anchor

"""

#sample
"""
读取图像中猫和狗的真实边界框，其中第一个二元素为类别(0为狗，1为猫)，剩余四个元素分别为左上角的x和y，以及右下角的x和y,(值域在[0,1])
此时通过左上角和右下角的坐标够早了5个需要标注的anchor,分别记为A0,...,A4

"""

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torch.utils.data as Data
import torchvision.transforms as transforms
import numpy as np
import math
from PIL import Image
import matplotlib.pyplot as plt

#加载和显示图像
img=Image.open('./catdog.jpg')
plt.imshow(img)
plt.show()
plt.close()

print(img.size) #值得注意的是，这里返回的是w*h
w,h=img.size

#画出这些anchor与ground truth在图像中的位置
bbox_scale=torch.tensor((w,h,w,h),dtype=torch.float32)

#ground_truth
#每一行表示的是图像中一个目标的ground-truth:[class,(bbox_coordinate)],注意需要尺度的恢复
ground_truth=torch.tensor([[0,0.1,0.08,0.52,0.92],
                           [1,0.55,0.2,0.9,0.88]])

#定义anchor
#anchor只是坐标
anchors=torch.tensor(
    [[0,0.1,0.2,0.3],
     [0.15,0.2,0.4,0.4],
     [0.63,0.05,0.88,0.98],
     [0.66,0.45,0.8,0.8],
     [0.57,0.3,0.92,0.9]]
)

def show_bboxes(axes,bboxes,labels=None,colors=None):
    def _make_list(obj,default_values=None):
        if obj is None:
            obj=default_values
        elif not isinstance(obj,(list,tuple)):
            obj=[obj]
        return obj
    labels=_make_list(labels)
    colors=_make_list(colors,['b','g','r','m','c'])

    for i,bbox in enumerate(bboxes): #索引一整行
        color=colors[i%len(colors)]

        rect=plt.Rectangle(
            xy=(bbox[0],bbox[1]),
            width=bbox[2]-bbox[0],
            height=bbox[3]-bbox[1],
            fill=False,
            linewidth=2
        )
        axes.add_patch(rect)
        if labels and len(labels)>i:
            text_color='k' if color=='w' else 'w' #相当于三目运算符，如果color==‘w',那么，text_color='k',否则，test_color='w'
            axes.text(rect.xy[0],rect.xy[1],labels[i],
                      va='center',ha='center',fontsize=6,
                      color=text_color,bbox=dict(facecolor=color,lw=0))

fig=plt.imshow(img)

#绘制ground-truth and anchor
show_bboxes(fig.axes,ground_truth[:,1:]*bbox_scale,['dog','cat'],'k')
show_bboxes(fig.axes,anchors*bbox_scale,['0','1','2','3','4'])

plt.show()


import torch
import torch.nn as nn
import torch.optim as optim
import config
import os
from dataset import MyTestDataset
from generator_model import Generator
from utils import save_test_examples, load_checkpoint
import argparse

def parser():
    parser = argparse.ArgumentParser(description="test.py: Model testing script of White-box Cartoonization. For inference, please refer to inference.py")
    parser.add_argument("--dataroot",default=config.VAL_PHOTO_DIR,
                        help="path to image data test folder. default path:"+f"{config.VAL_PHOTO_DIR}")
    parser.add_argument("--weight_path", default=os.path.join(config.CHECKPOINT_FOLDER, config.LOAD_CHECKPOINT_GEN),
                        help="path to model weight file. default path:"+f"{os.path.join(config.CHECKPOINT_FOLDER, config.LOAD_CHECKPOINT_GEN)}")
    parser.add_argument("--dest_folder",default=config.RESULT_TEST_DIR,
                        help="path to destination folder for saving images. default path:"+f"{config.RESULT_TEST_DIR}")
    parser.add_argument("--sample_size", type=int, default= 50,
                        help="only inference certain number of images. default=50.")
    parser.add_argument('--shuffle', action='store_true',
                        help="shuffle test data")
    parser.add_argument('--concat_img', action='store_true',
                        help="concat input and output images instead of separated save files")
    parser.add_argument('--no_post_processing', action='store_true',
                        help="disable post_processing (not recommended). This will probably cause output to have terrible noise")
    return parser.parse_args()

def check_arguments_errors(args):
    if not os.path.isdir(args.dataroot):
        raise(ValueError("Invalid image data folder path {}".format(os.path.abspath(args.dataroot))))
    if not os.path.isfile(args.weight_path):
        raise(ValueError("Invalid model weight path {}".format(os.path.abspath(args.weight_path))))

def test_fn(args):
    print("Using Device: " + config.DEVICE)
    gen = Generator(img_channels=3).to(config.DEVICE)
    opt_gen = optim.Adam(gen.parameters(), lr=config.LEARNING_RATE, betas=(0.5, 0.999))
    load_checkpoint(gen, opt_gen, config.LEARNING_RATE, path=args.weight_path)
    test_dataset = MyTestDataset(args.dataroot)

    shuffle = True if(args.shuffle) else False
    concat_img = True if(args.concat_img) else False
    post_processing = False if(args.no_post_processing) else True

    print("=> Saving Test outputs")
    print("="*80)
    save_test_examples(gen, test_dataset, dest_folder=args.dest_folder, num_samples=args.sample_size, shuffle=shuffle, concat_image=concat_img, post_processing=post_processing)
    print(f"=> Finished inferencing {args.sample_size} images")
    print("="*80)

if __name__ == "__main__":
    args = parser()
    check_arguments_errors(args)
    test_fn(args)


import sys
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import cross_validate
from sklearn.svm import SVR
from RegressionMetrics import RegressorMetrics
from numpy import arange
from timeit import default_timer as timer

# from numba import jit, cuda , float32
# @jit(target ="cuda")
# @cuda.jit
def gen(x):
    out = []
    out.append(x)
    while(x < 1):
        x = x * 10
        out.append(x)

    x = 2
    out.append(x)
    while(x <= 10000):
        x = x * 2
        out.append(x)

    return out
# def float_range(start, stop, step):
#   while start < stop:
#     yield float(start)
#     start += decimal.Decimal(step)

# @jit(target ="cuda")
# @cuda.jit
def svmRbf(data, labels, nof ,file , filename):
    start = timer()
    out = gen(0.00000001)
    params = {
        # 'C': out,
        'C': [0.1, 0.5, 1, 5, 10, 20],
        'gamma': arange(0.1 , 10.0 , 0.1),
        'kernel': ['rbf']
    }
    clf = GridSearchCV(SVR(), params, n_jobs=-1, cv=nof)
    clf.fit(data, labels)
    best_parameters = clf.best_params_
    c = best_parameters['C']
    gamma = best_parameters['gamma']

    model = SVR(C=c,kernel='rbf' , gamma= gamma)
    # cvs = cross_val_score(model, data, labels, cv=nof)
    # print(cvs)
    # print(cvs.mean() , "\t" , cvs.std())
    r = RegressorMetrics()
    r.set_predictorName("SVR_rbf")
    r.set_contin(False)
    r.set_DatasetName(filename)
    bestparameters = 'C= ' +str(c) + ' gamma= '+str(gamma)
    r.set_best(bestparameters)
    r.PrintbestParameters()

    cv_results = cross_validate(model, data, labels, cv=nof, scoring=r.scorer, return_train_score = True)
    r.Print("SVR_rbf")
    r.Print("test")
    r.PrintResults("MAE" , cv_results['test_MAE'])
    r.PrintResults("RMAE" , cv_results['test_RMAE'])
    r.PrintResults("MSE" , cv_results['test_MSE'])
    r.PrintResults("RMSE" , cv_results['test_RMSE'])
    r.PrintResults("RS" , cv_results['test_RS'])
    r.Print("train")
    r.PrintResults("MAE" , cv_results['train_MAE'])
    r.PrintResults("RMAE" , cv_results['train_RMAE'])
    r.PrintResults("MSE" , cv_results['train_MSE'])
    r.PrintResults("RMSE" , cv_results['train_RMSE'])
    r.PrintResults("RS" , cv_results['train_RS'])
    print("time:", timer()-start)

    # file.write(str(cv_results['test_MAE']))
    # file.write(str(cv_results['test_RMAE']))
    # file.write(str(cv_results['test_MSE']))
    # file.write(str(cv_results['test_RMSE']))
    # file.write(str(cv_results['test_RS']))


"""Plotting functions

This module contains various functions to plot graphs and algorithms.
"""

__author__ = 'Henry Robbins'
__all__ = ['tour_plot', 'tree_plot', 'dijkstras_plot', 'mst_algorithm_plot',
           'tsp_heuristic_plot', 'create_tour_plot',
           'create_spanning_tree_plot', 'assisted_mst_algorithm_plot',
           'assisted_dijkstras_plot']

import numpy as np
import pandas as pd
import networkx as nx
import warnings
from PIL import Image
import pkgutil
from typing import List, Tuple, Dict, Union
from .algorithms import (dijkstras, prims, kruskals, reverse_kruskals,
                         spanning_tree_cost, neighbor, insertion, two_opt,
                         tour_cost)
from bokeh.plotting import figure
from bokeh.models.widgets.markups import Div
from bokeh.models.widgets.tables import TableColumn, DataTable
from bokeh.models.renderers import GlyphRenderer
from bokeh.layouts import row, gridplot, GridBox
from bokeh.models import (HoverTool, TapTool, ColumnDataSource, LabelSet,
                          Button, CustomJS)

# Color Theme -- Using Google's Material Design Color System
# https://material.io/design/color/the-color-system.html

PRIMARY_COLOR = '#1565c0'
PRIMARY_LIGHT_COLOR = '#5e92f3'
PRIMARY_DARK_COLOR = '#003c8f'
SECONDARY_COLOR = '#d50000'
SECONDARY_LIGHT_COLOR = '#ff5131'
SECONDARY_DARK_COLOR = '#9b0000'
PRIMARY_FONT_COLOR = '#ffffff'
SECONDARY_FONT_COLOR = '#ffffff'
# Grayscale
TERTIARY_COLOR = '#DFDFDF'
TERTIARY_LIGHT_COLOR = 'white'  # Jupyter Notebook: white, Sphinx: #FCFCFC
TERTIARY_DARK_COLOR = '#404040'

NODE_SIZE = 11
NODE_LINE_WIDTH = 3
LINE_WIDTH = 5
PLOT_MARGIN = 0.085
# Order: image, underlay, glyph, guide, annotation, overlay
LABEL_LEVEL = 'annotation'
LABEL_BACKGROUND_LEVEL = 'guide'
NODE_LEVEL = 'glyph'
EDGE_LEVEL = 'underlay'
IMAGE_LEVEL = 'image'

CONSTANTS_JS = pkgutil.get_data(__name__, "resources/constants.js").decode()

tmp = pkgutil.get_data(__name__, "resources/plot_create.js")
PLOT_CREATE_JS = CONSTANTS_JS + tmp.decode()

tmp = pkgutil.get_data(__name__, "resources/plot_graph_iterations.js")
PLOT_GRAPH_ITERATIONS_JS = CONSTANTS_JS + tmp.decode()

# ------------------------
# Plotting Helper Fuctions
# ------------------------

def _graph_range(x:List[float], y:List[float]) -> List[float]:
    """Return x and y ranges that comfortably contain the given points.

    Args:
        x (List[float]): List of x-coordinates of the points.
        y (List[float]): List of y-coordinates of the points.

    Returns:
        List[float]: x-range (min_x, max_x) and y-range (min_y, max_y).
    """
    min_x, max_x = min(x), max(x)
    x_margin = PLOT_MARGIN * (max_x - min_x)
    min_x, max_x = min_x - x_margin, max_x + x_margin
    min_y, max_y = min(y), max(y)
    y_margin = PLOT_MARGIN * (max_y - min_y)
    min_y, max_y = min_y - y_margin, max_y + y_margin
    return (min_x, max_x, min_y, max_y)

def _blank_plot(G:nx.Graph,
                width:int = None,
                height:int = None,
                x_range:List[float] = None,
                y_range:List[float] = None,
                image:str = None, **kw) -> figure:
    """Return a blank bokeh plot.

    The x and y axis ranges are chosen from x_range and y_range first. If one
    or both are not specified then, it defaults to make all nodes of G visible
    or uses the dimensions of the image if an image was provided.

    Args:
        G (nx.Graph): Graph to be plotted on this blank plot.
        width (int, optional): Plot width. Defaults to None.
        height (int, optional): Plot height. Defaults to None.
        x_range (List[float], optional): Range of x-axis (min_x, max_x).
        y_range (List[float], optional): Range of y-axis (min_y, max_y).
        image (str, optional): Path to image file. Defaults to None.

    Returns:
        figure: Blank bokeh plot.
    """
    if x_range is not None and y_range is not None:
        min_x, max_x = x_range
        min_y, max_y = y_range
    else:
        if image is not None:
            im = Image.open(image)
            max_x, max_y = im.size
            min_x, min_y = 0,0
        else:
            x = nx.get_node_attributes(G,'x').values()
            y = nx.get_node_attributes(G,'y').values()
            min_x, max_x, min_y, max_y = _graph_range(x,y)
    plot = figure(x_range=(min_x, max_x),
                  y_range=(min_y, max_y),
                  title="",
                  width=400 if width is None else width,
                  height=400 if height is None else height)
    plot.toolbar.logo = None
    plot.toolbar_location = None
    plot.xgrid.grid_line_color = None
    plot.ygrid.grid_line_color = None
    plot.xaxis.visible = False
    plot.yaxis.visible = False
    plot.background_fill_color = None
    plot.border_fill_color = None
    plot.outline_line_color = None
    plot.toolbar.active_drag = None
    plot.toolbar.active_scroll = None
    if image is not None:
        _add_image(plot, image)
    return plot

def _add_image(plot:figure, image:str):
    """Add an image to the background of the plot.

    Args:
        plot (figure): Plot to add this image to.
        image (str): Path to image.
    """
    im = Image.open(image).convert('RGBA')
    xdim, ydim = im.size

    img = np.empty((ydim, xdim), dtype=np.uint32)
    view = img.view(dtype=np.uint8).reshape((ydim, xdim, 4))

    view[:,:,:] = np.flipud(np.asarray(im))

    plot.image_rgba(image=[img],
                    x=plot.x_range.start,
                    y=plot.y_range.start,
                    dw=plot.x_range.end - plot.x_range.start,
                    dh=plot.y_range.end - plot.y_range.start,
                    level="image")

def _edge_positions(G:nx.Graph,
                    edges:List[Tuple[float]],
                    return_type:str = 'List') -> Dict[Tuple[int], float]:
    """Return positional data for the edges of the graph.

    Args:
        G (nx.Graph): Graph (nodes must have pos attributes 'x' and 'y').
        edges (List[Tuple[float]]): Edges to compute positional data for.
        return_type (str): Return type. {'List', 'Dict'}.

    Returns:
        Dict[Tuple[int], float]: Dictionary from edges to positions
    """
    xs = {(u,v): (G.nodes[u]['x'], G.nodes[v]['x']) for u,v in edges}
    ys = {(u,v): (G.nodes[u]['y'], G.nodes[v]['y']) for u,v in edges}
    if return_type == 'Dict':
        return xs, ys
    else:
        return list(xs.values()), list(ys.values())

def _set_edge_positions(G:nx.Graph):
    """Add edge attribute with positional data.

    Args:
        G (nx.Graph): Graph to add positional attributes to.
    """
    xs, ys = _edge_positions(G, G.edges, return_type='Dict')
    nx.set_edge_attributes(G, xs, 'xs')
    nx.set_edge_attributes(G, ys, 'ys')

def _swap_positions(G:nx.Graph, swap:List[int]) -> List[List[float]]:
    """Return positional data for all edges in an edge swap.

    Args:
        G (nx.Graph): Networkx Graph.
        swap (List[int]): (u_1, u_2, v_1, v_2) where (u_1, u_2) and (v_1, v_2)
                          are swapped with (u_1, v_1) and (u_2, v_2).
    Returns:
        List[List[float]]: Positional data for all edges in an edge swap.
    """
    def get_coord(i):
        return G.nodes()[swap[i]]['x'], G.nodes()[swap[i]]['y']

    if swap is None:
        before_x, before_y, after_x, after_y = [[[],[]]] * 4
    else:
        (u1x, u1y) = get_coord(0)
        (u2x, u2y) = get_coord(1)
        (v1x, v1y) = get_coord(2)
        (v2x, v2y) = get_coord(3)
        before_x = [[u1x, u2x],[v1x, v2x]]
        before_y = [[u1y, u2y],[v1y, v2y]]
        after_x = [[u1x, v1x],[u2x, v2x]]
        after_y = [[u1y, v1y],[u2y, v2y]]
    return before_x, before_y, after_x, after_y

def _set_graph_colors(G:nx.Graph):
    """Add node/edge attribute with color data. Highlight edges.

    Args:
        G (nx.Graph): Graph to add color attributes to.
    """
    for u in G.nodes:
        G.nodes[u]['line_color'] = PRIMARY_DARK_COLOR
        G.nodes[u]['line_width'] = NODE_LINE_WIDTH
        G.nodes[u]['fill_color'] = PRIMARY_LIGHT_COLOR
    for u,v in G.edges:
        G[u][v]['line_color'] = TERTIARY_COLOR

def _add_nodes(G:nx.Graph,
               plot:figure) -> Union[ColumnDataSource, GlyphRenderer]:
    """Add nodes from G to the plot.

    Args:
        G (nx.Graph): Networkx graph.
        plot (figure): Plot to add the nodes to.

    Returns:
        Union[ColumnDataSource, GlyphRenderer]: node source and glyphs.
    """
    nodes_df = pd.DataFrame([G.nodes[u] for u in sorted(G.nodes())])
    nodes_src = ColumnDataSource(data=nodes_df.to_dict(orient='list'))

    nodes_glyph = plot.circle(x='x', y='y', size=NODE_SIZE, level=NODE_LEVEL,
                              line_color='line_color', fill_color='fill_color',
                              line_width='line_width',
                              nonselection_fill_alpha=1,
                              nonselection_line_alpha=1, source=nodes_src)

    return nodes_src, nodes_glyph

def _add_edges(G:nx.Graph,
               plot:figure,
               show_labels:bool = True,
               hover_line_color:str = TERTIARY_DARK_COLOR
               ) -> Union[ColumnDataSource, GlyphRenderer]:
    """Add edges from G to the plot.

    Args:
        G (nx.Graph): Networkx graph.
        plot (figure): Plot to add the edges to.
        show_labels (bool): True iff each edge should be labeled.
        hover_line_color (str): Color of the edges when hovering over them.

    Returns:
        Union[ColumnDataSource, GlyphRenderer]: edge source and glyphs.
    """
    edges_df = pd.DataFrame([G[u][v] for u,v in G.edges()])
    u,v = zip(*[(u,v) for u,v in G.edges])
    edges_df['u'] = u
    edges_df['v'] = v
    edges_src = ColumnDataSource(data=edges_df.to_dict(orient='list'))

    edges_glyph = plot.multi_line(xs='xs', ys='ys',
                                  line_color='line_color',
                                  line_cap='round',
                                  hover_line_color=hover_line_color,
                                  line_width=LINE_WIDTH,
                                  nonselection_line_alpha=1,
                                  level=EDGE_LEVEL,
                                  source=edges_src)

    if show_labels:
        _add_labels(G, plot)

    return edges_src, edges_glyph

def _add_labels(G:nx.Graph, plot:figure):
    """Add labels from G to the plot.

    Args:
        G (nx.Graph): Networkx graph.
        plot (figure): Plot to add the labels to.
    """
    text = [round(w,2) for w in nx.get_edge_attributes(G,'weight').values()]
    xs = np.array(list(nx.get_edge_attributes(G, 'xs').values()))
    ys = np.array(list(nx.get_edge_attributes(G, 'ys').values()))

    x_range = (plot.x_range.end - plot.x_range.start)
    y_range = (plot.y_range.end - plot.y_range.start)
    margin_shift_x = (x_range / (2 * PLOT_MARGIN + 1)) * PLOT_MARGIN
    margin_shift_y = (y_range / (2 * PLOT_MARGIN + 1)) * PLOT_MARGIN
    x_scale = plot.width / x_range
    y_scale = plot.height / y_range

    xs = (xs + margin_shift_x - plot.x_range.start) * x_scale
    ys = (ys + margin_shift_y - plot.y_range.start) * y_scale

    x = np.mean(xs, axis=1)
    y = np.mean(ys, axis=1)
    centers = np.vstack((x,y)).T
    v = np.vstack((xs[:,1] - xs[:,0], ys[:,1] - ys[:,0])).T
    n = np.divide(v.T, np.linalg.norm(v, axis=1)).T

    lbl_size = np.array([len(str(w)) for w in text]) * 3
    tmp = np.multiply(n, lbl_size[:, np.newaxis])
    blank_start = centers - (n * 3 + tmp)
    blank_end = centers + (n * 3 + tmp)
    blank_xs = np.vstack((blank_start[:,0], blank_end[:,0])).T
    blank_ys = np.vstack((blank_start[:,1], blank_end[:,1])).T

    x = (x / x_scale) - margin_shift_x + plot.x_range.start
    y = (y / y_scale) - margin_shift_y + plot.y_range.start
    blank_xs = (blank_xs / x_scale) - margin_shift_x + plot.x_range.start
    blank_ys = (blank_ys / y_scale) - margin_shift_y + plot.y_range.start

    plot.multi_line(xs=blank_xs.tolist(), ys=blank_ys.tolist(),
                    line_color='white', line_width=LINE_WIDTH+1,
                    nonselection_line_alpha=1, level=LABEL_BACKGROUND_LEVEL)

    labels_src = ColumnDataSource(data={'x': x, 'y': y, 'text': text})
    labels = LabelSet(x='x', y='y', text='text', text_align='center',
                      text_baseline='middle', text_font_size='13px',
                      text_color='black', level=LABEL_LEVEL, source=labels_src)
    plot.add_layout(labels)

def _get_create_divs(plot:figure,
                     cost_txt:str = '0.0',
                     click_txt:str = '[]') -> Tuple[Div]:
    """Return the Divs shown by plots in which a tour or tree is created.

    Args:
        plot (figure): The plot to which these Divs are added.
        cost_text (str, optional): Current cost of solution. Defaults to '0.0'.
        clicked_text (str, optional): Clicked objects. Defaults to '[]'.
    """
    cost = Div(text=cost_txt, width=int(plot.width/3), align='center')
    clicked = Div(text=click_txt, width=int(plot.width/3), align='center')
    error_msg = Div(text='', width=int(plot.width/3), align='center')
    return (cost, clicked, error_msg)

def _get_blank_src_data(G:nx.Graph) -> Dict[str, List[int]]:
    """Return default source data for plotting the given graph.

    Args:
        G (nx.Graph): Graph that is being plotted.

    Returns:
        Dict[str, List[int]]: Default source data.
    """
    return {'visited': [],
            'unvisited': list(range(len(G))),
            'tree_edges': [],
            'edge_ids': [],
            'clicked': []}

def _edge_src_maps(G:nx.Graph,
                   edges_src:ColumnDataSource) -> Tuple[List[List[float]]]:
    """Return JS friendly maps from edges to edge_ids and weights.

    Args:
        G (nx.Graph): Graph containing these edges.
        edges_src (ColumnDataSource): Data source for edges.

    Returns:
        Tuple[List[List[float]]]: edge_ids map and weights map.
    """
    edge_ids = np.zeros((len(G), len(G)))
    G_matrix = np.zeros((len(G), len(G)))
    edge_pairs = list(zip(edges_src.data['u'], edges_src.data['v']))
    for i in range(len(edge_pairs)):
        u,v = edge_pairs[i]
        edge_ids[u][v] = i
        edge_ids[v][u] = i
        G_matrix[u][v] = G[u][v]['weight']
        G_matrix[v][u] = G[v][u]['weight']
    return edge_ids.tolist(), G_matrix.tolist()

def _add_tools(plot:figure,
               on_click:str,
               nodes_glyph:GlyphRenderer,
               renderer:GlyphRenderer, **kw):
    """Add hover and tap tools to the plot.

    Args:
        plot (figure): Plot to add these tools to.
        on_click (str): JS code to be run when the renderer is clicked.
        nodes_glyph (GlyphRenderer): Glyph for the nodes on this plot.
        renderer (GlyphRenderer): Renderer that should call on_click code.
    """
    on_hover_code = "source.data['last_index'] = cb_data.index.indices[0]"
    plot.add_tools(HoverTool(tooltips=[("Index", "$index"),
                                       ("Name", "@name")],
                             renderers=[nodes_glyph]),
                   HoverTool(tooltips=None,
                             callback=CustomJS(args=dict(source=kw['source']),
                                               code=on_hover_code),
                             renderers=[renderer]),
                   TapTool(callback=CustomJS(args=kw,
                                             code=on_click),
                           renderers=[renderer]))

def _get_grid(plot:figure,
              cost:Div,
              error_msg:Div,
              clicked:Div) -> GridBox:
    """Return a grid containing the given plot and divs

    Args:
        plot (figure): The plot to be in the grid.
        cost_text (Div): Current cost of solution.
        error_msg (Div): Error message.
        clicked_text (Div): Clicked objects.

    Returns:
        GridBox: grid containing the given plot and divs.
    """
    return gridplot([[plot],
                     [row(cost,error_msg,clicked)]],
                    toolbar_location=None,
                    toolbar_options={'logo': None})

# ------------------------
# Static Plotting Fuctions
# ------------------------

def _graph_plot(G:nx.Graph,
                edges:List[Tuple[int]],
                cost:float = None,
                show_all_edges:bool = True,
                show_labels:bool = True, **kw) -> GridBox:
    """Return a plot of the graph G with given edges highlighted.

    Args:
        G (nx.Graph): Graph to be plotted.
        edges (List[Tuple[int]]): Edges to be highlighted.
        cost (float, optional): Cost to be displayed. Defaults to None.
        show_all_edges (bool, optional): True iff all edges should be shown.
        show_labels (bool, optional): True iff labels should be shown.

    Returns:
        GridBox: Plot of the graph G with given edges highlighted.
    """
    G = G.copy()
    plot = _blank_plot(G, **kw)

    _set_edge_positions(G)
    _set_graph_colors(G)

    nodes_src, nodes_glyph = _add_nodes(G, plot)
    if show_all_edges:
        edges_src, edges_glyph = _add_edges(G, plot, show_labels=show_labels)

    if len(edges) > 0:
        xs, ys = _edge_positions(G, edges)
        plot.multi_line(xs=xs, ys=ys, line_cap='round', line_width=LINE_WIDTH,
                        line_color=TERTIARY_DARK_COLOR, level=EDGE_LEVEL)

    cost_txt = '' if cost is None else ('%.1f' % cost)
    cost = Div(text=cost_txt, width=int(plot.width/2), align='center')

    plot.add_tools(HoverTool(tooltips=[("Index", "$index"),
                                       ("Name", "@name")],
                             renderers=[nodes_glyph]))
    grid = gridplot([[plot],
                     [row(cost)]],
                    toolbar_location=None,
                    toolbar_options={'logo': None})

    return grid

def tour_plot(G:nx.Graph, tour:List[int], **kw) -> GridBox:
    """Return a plot of the tour on graph G.

    Args:
        G (nx.Graph): Networkx graph.
        tour (List[int]): Tour of the graph.

    Returns:
        GridBox: Plot of the tour on graph G.
    """
    cost = tour_cost(G, tour)
    edges = [(tour[i], tour[i+1]) for i in range(len(tour)-1)]
    return _graph_plot(G=G, show_all_edges=False, show_labels=False,
                       edges=edges, cost=cost, **kw)

def tree_plot(G:nx.Graph,
              tree:List[Tuple[int]],
              show_cost:bool = False, **kw):
    """Return a plot of the tree on graph G.

    Args:
        G (nx.Graph): Networkx graph.
        tree (List[int]): List of edges in the tree.
        show_cost (bool): True if cost of tree should be shown on plot.

    Returns:
        GridBox: Plot of the tree on graph G.
    """
    cost = spanning_tree_cost(G, tree) if show_cost else None
    return _graph_plot(G=G, show_all_edges=True, show_labels=True,
                       edges=tree, cost=cost, **kw)

# ----------------------------
# Non-Static Plotting Fuctions
# ----------------------------

def _graph_iterations_plot(G:nx.Graph,
                           nodes:List[List[int]] = None,
                           edges:List[List[List[int]]] = None,
                           costs:List[float] = None,
                           tables:List[pd.DataFrame] = None,
                           swaps:List[List[int]] = None,
                           show_all_edges:bool = True,
                           show_labels:bool = True, **kw) -> GridBox:
    """Return a plot of multiple iterations of a graph.

    Args:
        G (nx.Graph): Networkx graph.
        nodes (List[List[int]]): Highlighted nodes at every iteration.
        edges (List[List[List[int]]]): Highlighted edges at every iteration.
        costs (List[float]): Cost at every iteration.
        tables (List[pd.DataFrame]): Table to be shown at every iteration.
        swaps (List[List[int]]): Edge swap to highlight at every iteration.
        show_all_edges (bool, optional): True iff all edges should be shown.
        show_labels (bool, optional): True iff labels should be shown.

    Returns:
        GridBox: Plot of multiple iterations of a graph.
    """
    G = G.copy()
    plot = _blank_plot(G, **kw)

    _set_edge_positions(G)
    _set_graph_colors(G)

    args_dict = {}  # keep track of objects to pass to JS callback

    # nodes and edges
    nodes_src, nodes_glyph = _add_nodes(G, plot)
    args_dict['nodes_src'] = nodes_src
    if nodes is not None:
        for i in nodes[0]:
            nodes_src.data['line_color'][i] = PRIMARY_DARK_COLOR
            nodes_src.data['fill_color'][i] = PRIMARY_DARK_COLOR

    if show_all_edges:
        edges_src, edges_glyph = _add_edges(G, plot, show_labels=show_labels)

    # current iteration
    n = Div(text='0', width=plot.width, align='center')
    args_dict['n'] = n

    # total number of iterations
    features = [edges, nodes, costs, tables, swaps]
    k = max([0 if feature is None else len(feature) for feature in features])
    k = Div(text=str(k), width=plot.width, align='center')
    args_dict['k'] = k

    # indicate if on final iteration
    done = Div(text='', width=int(plot.width/2), align='center')
    args_dict['done'] = done

    source_data = {}

    if edges is not None:
        tmp = list(zip(*[_edge_positions(G, edge) for edge in edges]))
        edge_xs, edge_ys = tmp
        source_data['edge_xs'] = edge_xs
        source_data['edge_ys'] = edge_ys
        edge_subset_src = ColumnDataSource(data={'xs': edge_xs[0],
                                                 'ys': edge_ys[0]})
        plot.multi_line('xs', 'ys', line_color=TERTIARY_DARK_COLOR,
                        line_width=LINE_WIDTH, level=EDGE_LEVEL,
                        line_cap='round', source=edge_subset_src)
        args_dict['edge_subset_src'] = edge_subset_src

    if nodes is not None:
        source_data['nodes'] = nodes

    if costs is not None:
        source_data['costs'] = costs
        cost = Div(text=str(costs[0]),
                   width=int(plot.width/2),
                   align='center')
        args_dict['cost'] = cost

    if tables is not None:
        tables = [table.to_dict(orient='list') for table in tables]
        source_data['tables'] = tables
        table_src = ColumnDataSource(data=tables[0])
        columns = [TableColumn(field='index', title='')]
        for i in range(len(tables[0])-1):
            columns.append(TableColumn(field=str(i), title=str(i)))
        table = DataTable(source=table_src, columns=columns, height=80,
                          background='white', index_position=None,
                          editable=False, reorderable=False, sortable=False,
                          selectable=False, width=plot.width)
        args_dict['table_src'] = table_src

    if swaps is not None:
        tmp = list(zip(*[_swap_positions(G, swap) for swap in swaps]))
        swaps_before_x, swaps_before_y, swaps_after_x, swaps_after_y = tmp
        source_data['swaps_before_x'] = swaps_before_x
        source_data['swaps_before_y'] = swaps_before_y
        source_data['swaps_after_x'] = swaps_after_x
        source_data['swaps_after_y'] = swaps_after_y
        swaps_src = ColumnDataSource(data={'swaps_before_x': swaps_before_x[0],
                                           'swaps_before_y': swaps_before_y[0],
                                           'swaps_after_x': swaps_after_x[0],
                                           'swaps_after_y': swaps_after_y[0]})
        plot.multi_line(xs='swaps_before_x', ys='swaps_before_y',
                        line_color=SECONDARY_COLOR, line_width=LINE_WIDTH,
                        line_cap='round', level=EDGE_LEVEL, source=swaps_src)
        plot.multi_line(xs='swaps_after_x', ys='swaps_after_y',
                        line_color=SECONDARY_COLOR, line_width=LINE_WIDTH,
                        line_cap='round', level=EDGE_LEVEL,
                        line_dash='dashed', source=swaps_src)
        args_dict['swaps_src'] = swaps_src

    source = ColumnDataSource(data=source_data)
    args_dict['source'] = source

    code = ('done_update()\n'
            + 'cost_update()\n'*(costs is not None)
            + 'edge_subset_update()\n'*(edges is not None)
            + 'table_update()\n'*(tables is not None)
            + 'nodes_update()\n'*(nodes is not None)
            + 'swaps_update()\n'*(swaps is not None))
    next_btn_code = PLOT_GRAPH_ITERATIONS_JS + 'increment_iteration()\n' + code
    prev_btn_code = PLOT_GRAPH_ITERATIONS_JS + 'decrement_iteration()\n' + code

    # buttons
    next_button = Button(label="Next", button_type="primary",
                         max_width=int(plot.width/2),
                         width_policy='fit', sizing_mode='stretch_width')
    next_button.js_on_click(CustomJS(args=args_dict, code=next_btn_code))
    prev_button = Button(label="Previous", button_type="primary",
                         max_width=int(plot.width/2),
                         width_policy='fit', sizing_mode='stretch_width')
    prev_button.js_on_click(CustomJS(args=args_dict, code=prev_btn_code))

    plot.add_tools(HoverTool(tooltips=[("Index", "$index"),
                                       ("Name", "@name")],
                             renderers=[nodes_glyph]))

    # create layout
    layout = [[plot],
              [row(prev_button, next_button,
                   max_width=plot.width, sizing_mode='stretch_both')],
              [row(cost, done) if costs else row(done)]]
    if tables is not None:
        layout.insert(1, [table])

    grid = gridplot(layout,
                    toolbar_location=None,
                    toolbar_options={'logo': None})

    return grid

def dijkstras_plot(G:nx.Graph, s:int = 0, **kw) -> GridBox:
    """Return plot of Dijkstra's algorithm running on graph G with source s.

    Args:
        G (nx.Graph): Networkx graph.
        s (int): Source vertex to run the algorithm from. (Defaults to 0)

    Returns:
        GridBox: Plot of Dijkstra's algorithm running on graph G with source s.
    """
    nodes, trees, tables = dijkstras(G, s=s, iterations=True)
    return _graph_iterations_plot(G, nodes=nodes, edges=trees,
                                  tables=tables, **kw)

def mst_algorithm_plot(G:nx.Graph, algorithm:str, **kw) -> GridBox:
    """Return plot of the given MST algorithm running on the graph G.

    Args:
        G (nx.Graph): Networkx graph.
        algorithm (str): {'prims', 'kruskals', 'reverse_kruskals'}

    Returns:
        GridBox: Plot of the given MST algorithm running on the graph G.
    """
    if algorithm == 'prims':
        trees = prims(G, i=kw['i'], iterations=True)
    elif algorithm == 'kruskals':
        trees = kruskals(G, iterations=True)
    elif algorithm == 'reverse_kruskals':
        trees = reverse_kruskals(G, iterations=True)
    nodes = []
    for tree in trees:
        nodes.append(list(set([item for sublist in tree for item in sublist])))
    costs = [spanning_tree_cost(G, tree) for tree in trees]
    return _graph_iterations_plot(G, nodes=nodes, edges=trees,
                                  costs=costs, **kw)

def tsp_heuristic_plot(G:nx.Graph, algorithm:str, **kw) -> GridBox:
    """Return a plot of the given TSP heuristic running on G.

    Args:
        G (nx.Graph): Networkx graph.
        algorithm (str): {'random_neighbor', 'nearest_neighbor',
                          'nearest_insertion', 'furthest_insertion', '2-OPT'}

    Returns:
        GridBox: Plot of the given TSP heuristic running on G.
    """
    swaps = None
    if algorithm == 'random_neighbor':
        tours = neighbor(G, i=kw['i'],
                         nearest=False, iterations=True)
        if len(tours) > 2:
            del tours[-2]
    elif algorithm == 'nearest_neighbor':
        tours = neighbor(G, i=kw['i'],
                         nearest=True, iterations=True)
        if len(tours) > 2:
            del tours[-2]
    elif algorithm == 'nearest_insertion':
        tours = insertion(G, initial_tour=kw['initial_tour'],
                          nearest=True, iterations=True)
    elif algorithm == 'furthest_insertion':
        tours = insertion(G, initial_tour=kw['initial_tour'],
                          nearest=False, iterations=True)
    elif algorithm == '2-OPT':
        tours, swaps = two_opt(G, tour=kw['tour'], iterations=True)
    nodes = tours
    edges = []
    for tour in tours:
        edges.append([(tour[i], tour[i+1]) for i in range(len(tour)-1)])
    costs = [tour_cost(G, tour) for tour in tours]
    return _graph_iterations_plot(G, nodes=nodes, edges=edges, costs=costs,
                                  swaps=swaps, show_all_edges=False,
                                  show_labels=False, **kw)

# -----------------------------
# Interactive Plotting Fuctions
# -----------------------------

def create_tour_plot(G:nx.Graph, **kw) -> GridBox:
    """Return a plot in which you can create a tour.

    Args:
        G (nx.Graph): Networkx graph.

    Rerturns:
        GridBox: Plot in which you can create a tour.
    """
    G = G.copy()
    plot = _blank_plot(G, **kw)

    _set_edge_positions(G)
    _set_graph_colors(G)
    nodes_src, nodes_glyph = _add_nodes(G, plot)

    # docs indicate that each value should be of the same length but this works
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        source = ColumnDataSource(data=_get_blank_src_data(G))

    G_matrix = nx.adjacency_matrix(G).todense().tolist()
    cost_matrix = ColumnDataSource(data={'G': G_matrix})

    tour_src = ColumnDataSource(data={'edges_x': [],
                                      'edges_y': []})
    plot.line(x='edges_x', y='edges_y', line_color=TERTIARY_DARK_COLOR,
              line_cap='round', line_width=LINE_WIDTH, level=EDGE_LEVEL,
              source=tour_src)

    cost, clicked, error_msg = _get_create_divs(plot)

    on_click = PLOT_CREATE_JS + 'check_done()\ncreate_tour_on_click()\n'

    _add_tools(plot, on_click=on_click, nodes_glyph=nodes_glyph,
               renderer=nodes_glyph, source=source, nodes_src=nodes_src,
               tour_src=tour_src, cost_matrix=cost_matrix, cost=cost,
               error_msg=error_msg, clicked=clicked)

    return _get_grid(plot, cost, error_msg, clicked)

def create_spanning_tree_plot(G:nx.Graph, **kw) -> GridBox:
    """Return a plot in which you can create a spanning tree.

    Args:
        G (nx.Graph): Networkx graph.

    Returns:
        GridBox: Plot in which you can create a spanning tree.
    """
    G = G.copy()
    plot = _blank_plot(G, **kw)

    _set_edge_positions(G)
    _set_graph_colors(G)

    nodes_src, nodes_glyph = _add_nodes(G, plot)
    edges_src, edges_glyph = _add_edges(G, plot, show_labels=True)

    src_data = _get_blank_src_data(G)
    edge_ids, G_matrix = _edge_src_maps(G, edges_src)
    src_data['edge_ids'] = edge_ids
    cost_matrix = ColumnDataSource(data={'G': G_matrix})

    # docs indicate that each value should be of the same length but this works
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        source = ColumnDataSource(data=src_data)

    cost, clicked, error_msg = _get_create_divs(plot)

    code = PLOT_CREATE_JS
    on_click = code + "check_done()\nload_data()\nselect_edge()\ntree_update()"

    _add_tools(plot, on_click=on_click, nodes_glyph=nodes_glyph,
               renderer=edges_glyph, source=source, nodes_src=nodes_src,
               edges_src=edges_src, cost_matrix=cost_matrix, cost=cost,
               error_msg=error_msg, clicked=clicked)

    return _get_grid(plot, cost, error_msg, clicked)

def assisted_dijkstras_plot(G, s=0, **kw) -> GridBox:
    """Return a plot in which the user creates a shortest path tree from s.

    Args:
        G (nx.Graph): Networkx graph.
        s (int): The vertex to generate a shortest path tree from.

    Returns:
        GridBox: Plot in which the user creates a shortest path tree from s.
    """
    G = G.copy()
    plot = _blank_plot(G, **kw)

    _set_edge_positions(G)
    _set_graph_colors(G)

    nodes_src, nodes_glyph = _add_nodes(G, plot)
    nodes_src.data['fill_color'][s] = SECONDARY_COLOR
    nodes_src.data['line_color'][s] = SECONDARY_DARK_COLOR
    edges_src, edges_glyph = _add_edges(G, plot, show_labels=True)

    src_data = _get_blank_src_data(G)
    dist = [float('inf')]*len(G)
    dist[s] = 0
    src_data['dist'] = dist
    src_data['prev'] = [float('nan')]*len(G)
    src_data['settled'] = []
    src_data['frontier'] = [s]

    edge_ids, G_matrix = _edge_src_maps(G, edges_src)
    src_data['edge_ids'] = edge_ids
    cost_matrix = ColumnDataSource(data={'G': G_matrix})

    # docs indicate that each value should be of the same length but this works
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        source = ColumnDataSource(data=src_data)

    error_msg = Div(text='', width=int(plot.width/3), align='center')

    table_data = {str(i): ['inf', '-'] for i in range(len(G))}
    table_data['index'] = ['label', 'prev']

    table_data[str(s)][1] = '0'
    table_src = ColumnDataSource(data=table_data)
    columns = [TableColumn(field='index', title='')]
    for i in range(len(G)):
        columns.append(TableColumn(field=str(i), title=str(i)))
    table = DataTable(source=table_src, columns=columns, height=80,
                      background='white', index_position=None, editable=False,
                      reorderable=False, sortable=False, selectable=False,
                      width=plot.width)

    on_click = PLOT_CREATE_JS + 'check_done()\nload_data()\ndijkstras()\n'

    _add_tools(plot, on_click=on_click, nodes_glyph=nodes_glyph,
               renderer=nodes_glyph, source=source, nodes_src=nodes_src,
               edges_src=edges_src, cost_matrix=cost_matrix,
               error_msg=error_msg, table_src=table_src)

    grid = gridplot([[plot],
                     [table],
                     [row(error_msg)]],
                    toolbar_location=None,
                    toolbar_options={'logo': None})

    return grid

def assisted_mst_algorithm_plot(G:nx.Graph, algorithm:str, **kw) -> GridBox:
    """Return a plot in which the user creates an MST with the given algorithm.

    Args:
        G (nx.Graph): Networkx graph.
        algorithm (str): {'prims', 'kruskals', 'reverse_kruskals'}

    Returns:
        GridBox: Plot in which the user creates an MST with given algorithm.
    """
    G = G.copy()
    plot = _blank_plot(G, **kw)

    _set_edge_positions(G)
    _set_graph_colors(G)

    nodes_src, nodes_glyph = _add_nodes(G, plot)
    if 's' in kw:
        nodes_src.data['fill_color'][kw['s']] = PRIMARY_DARK_COLOR
        nodes_src.data['line_color'][kw['s']] = PRIMARY_DARK_COLOR
    if algorithm == 'reverse_kruskals':
        hover_color = TERTIARY_COLOR
    else:
        hover_color = TERTIARY_DARK_COLOR
    edges_src, edges_glyph = _add_edges(G, plot, show_labels=True,
                                        hover_line_color=hover_color)

    src_data = _get_blank_src_data(G)
    if algorithm == 'prims':
        unvisited = list(range(len(G)))
        unvisited.remove(kw['s'])
        src_data['visited'] = [kw['s']]
        src_data['unvisited'] = unvisited
    elif algorithm == 'kruskals':
        edges = nx.get_edge_attributes(G,'weight')
        edges = list(dict(sorted(edges.items(), key=lambda item: item[1])))
        src_data['sorted_edges'] = edges
        src_data['forest'] = list(range(len(G)))
        src_data['index'] = [0]
    elif algorithm == 'reverse_kruskals':
        src_data['visited'] = list(range(len(G)))
        src_data['unvisited'] = []
        src_data['tree_edges'] = list(range(len(G.edges)))
        edges = nx.get_edge_attributes(G,'weight')
        edges = sorted(edges.items(), key=lambda item: item[1], reverse=True)
        edges = list(dict(edges))
        src_data['sorted_edges'] = edges
        src_data['index'] = [0]
        edges_src.data['line_color'] = [TERTIARY_DARK_COLOR]*len(G.edges())
        nodes_src.data['fill_color'] = [PRIMARY_DARK_COLOR]*len(G)

    edge_ids, G_matrix = _edge_src_maps(G, edges_src)
    src_data['edge_ids'] = edge_ids
    cost_matrix = ColumnDataSource(data={'G': G_matrix})

    # docs indicate that each value should be of the same length but this works
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        source = ColumnDataSource(data=src_data)

    if algorithm == 'reverse_kruskals':
        cost_text = '%.1f' % spanning_tree_cost(G, G.edges)
        clicked_edges = [str(x).replace(' ', '') for x in list(G.edges)]
        click_txt = '[' + ','.join(clicked_edges) + ']'
        cost, clicked, error_msg = _get_create_divs(plot, cost_txt=cost_text,
                                                    click_txt=click_txt)
    else:
        cost, clicked, error_msg = _get_create_divs(plot)

    code = 'check_done()\nload_data()\n%s()\ntree_update()\n' % (algorithm)
    on_click = PLOT_CREATE_JS + code

    _add_tools(plot, on_click=on_click, nodes_glyph=nodes_glyph,
               renderer=edges_glyph, source=source, nodes_src=nodes_src,
               edges_src=edges_src, cost_matrix=cost_matrix, cost=cost,
               error_msg=error_msg, clicked=clicked)

    return _get_grid(plot, cost, error_msg, clicked)


"""
[전화번호 목록]
전화번호부에 적힌 전화번호를 담은 배열 phone_book 이 solution 함수의 매개변수로 주어질 때,
어떤 번호가 다른 번호의 접두어인 경우가 있으면 false를 그렇지 않으면 true를 return 하도록 solution 함수를 작성하기
"""
from typing import List

def solution01(phone_book:List) -> bool:
    """어떤 번호가 다른 번호의 접두어로 존재하는지 판단하는 함수

    Args:
        phone_book (List): 전화번호부에 적힌 전화번호를 담은 배열

    Returns:
        bool: false이면 다른 번호의 접두어인 번호가 존재 / true이면 존재하지 않음

    - 해시 방식으로 구현하는 방법이 떠오르지 않아 완전 탐색을 사용
    - 테스트 20개 중 4개 통과 실패 -> startswith로 바꾼 후, 모두 통과
    - 시간 통과 x
    - deepcopy를 사용할 경우 테스트 20: 4023.52ms, 10.6MB
    - deepcopy를 사용하지 않을 경우 테스트 20: 통과 495.95ms, 10.4MB
    """

    total_length = len(phone_book)
    answer = True

    for i in range(total_length):
        pivot = phone_book[i]
        for phone_number in phone_book:
            if pivot == phone_number:
                continue
            # elif pivot in phone_number: # 접두어가 아닌 경우도 포함되므로 틀린 케이스가 존재
            elif phone_number.startswith(pivot):
                answer = False

    return answer

def solution02(phone_book:List) -> bool:
    """
    sort를 사용하여 비슷한 문자열끼리 인접하도록 순서를 바꾼다.
    그후, 인덱스를 하나만 어긋나게 뽑아내어 startswith를 사용하여 접두어인지 유무를 확인한다.

    모든 테스트를 통과했고, 시간 효율성도 통과한 경우다.

    하지만, 해쉬를 사용하지 않은 방식이다.
    """

    phone_book.sort()

    for p1, p2 in zip(phone_book, phone_book[1:]):
        if p2.startswith(p1):
            return False
    return True

def solution03(phone_book:List) -> bool:
    """
    프로그래머스에 아래 코드로 해쉬를 이용한 정석 풀이라고 한다.
    하지만, ["119", "5521194421"]인 경우 True임에도 불구하고 False를 반환하므로 잘못된 예시다.
    """

    # 해쉬화
    hash_phone_book = dict()
    for phone_number in phone_book:
        hash_phone_book[phone_number] = 1

    for phone_number in phone_book:
        arr = ''
        for num in phone_number:
            arr += num
            if phone_number in hash_phone_book and arr != phone_number:
                return False

def solution04(phone_book:List) -> bool:
    """
    해쉬와 startswith를 모두 사용하는 방식을 고려하여 알고리즘을 짜는 중
    """

    hashed_phone_book = dict()
    for phone_number in phone_book:
        hashed_phone_book[phone_number] = phone_number

    for phone_number in phone_book:
        if phone_number in hashed_phone_book and phone_number != hashed_phone_book[phone_number]:

            pass

if __name__ == "__main__":
    phone_book_list = [["119", "5521194421"], ["119", "97674223", "1195524421"], ["123","456","789"], ["12","123","1235","567","88"]]
    for phone_book in phone_book_list:
        print('-------- solution 01 -----')
        print(solution01(phone_book))
        print('-------- solution 02 -----')
        print(solution02(phone_book))
        print('-------- solution 03 -----')
        print(solution03(phone_book))
        print('-------- solution 04 -----')
        print(solution04(phone_book))


"""Site theme per user

Revision ID: e73842c57ec7
Revises: 8e8ba38bf52e
Create Date: 2022-04-16 16:03:50.623816

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'e73842c57ec7'
down_revision = '8e8ba38bf52e'
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.add_column('users', sa.Column('site_theme', sa.String(length=255), nullable=True))
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('users', 'site_theme')
    # ### end Alembic commands ###


import numpy as np
import scipy.special
import scipy.linalg

from src.classes import Atom
from src.classes import Vector
from src.radial_part import compute_radial_part
from src.gaunt_integral import compute_real_sph_harm

from matplotlib import pyplot

LMAX = 2
cg_coefficients = np.load("cg-coefficients.npy")

atoms = [
    Atom([0, 0, 0], atomic_number=1, radius_muffintin=1)
]

def modified_spherical_hankel_function(order, x):
    if order == 0:
        return np.exp(-x) / x
    elif order == 1:
        return -np.exp(-x) * (x + 1) / x ** 2
    elif order == 2:
        return np.exp(-x) * (x ** 2 + 3 * x + 3) / x ** 3

def modified_spherical_hankel_function_derivative(order, x):
    if order == 0:
        return -np.exp(-x) * (x + 1) / x ** 2
    elif order == 1:
        return np.exp(-x) * (x * (x + 2) + 2) / x ** 3
    elif order == 2:
        return -np.exp(-x) / x**4 * (x * (x * (x + 4) + 9) + 9)

determinants = []
energies = np.linspace(-0.8, -1.5, 100)

matrix_indices = []

for p in range(len(atoms)):
    for l in range(0, LMAX + 1):
        for m in range(-l, l + 1):
            matrix_indices.append((p, l, m))

for energy in energies:
    diagonal_elements = []

    potential = 0
    k = np.sqrt(np.abs(energy - potential))

    for atom in atoms:
        for l in range(0, LMAX + 1):
            R_normalized = compute_radial_part(energy, l, atom.atomic_number, atom.radius_muffintin)

            if energy > potential:
                j1 = scipy.special.spherical_jn(l, k * atom.radius_muffintin)
                f1 = scipy.special.spherical_yn(l, k * atom.radius_muffintin)

                j1_derivative = scipy.special.spherical_jn(l, k * atom.radius_muffintin, True)
                f1_derivative = scipy.special.spherical_yn(l, k * atom.radius_muffintin, True)
            else:
                j1 = scipy.special.spherical_in(l, k * atom.radius_muffintin)
                f1 = modified_spherical_hankel_function(l, k * atom.radius_muffintin)

                j1_derivative = scipy.special.spherical_in(l, k * atom.radius_muffintin, True)
                f1_derivative = modified_spherical_hankel_function_derivative(l, k * atom.radius_muffintin)

            t = -(
                (j1 * R_normalized[2][-1] - j1_derivative * R_normalized[1][-1])
                / (f1 * R_normalized[2][-1] - f1_derivative * R_normalized[1][-1])
            )

            for m in range(-l, l + 1):
                diagonal_elements.append(1.0 / t)

    matrix = np.diag(diagonal_elements)

    for i, (p1, l1, m1) in enumerate(matrix_indices):
        for j, (p2, l2, m2) in enumerate(matrix_indices):
            if p1 == p2: continue

            interatomic_vector = Vector(atoms[p2].position.cartesian - atoms[p1].position.cartesian)

            if energy > potential:
                result = 0

                for l in range(0, LMAX + 1):
                    for m in range(-l, l + 1):
                        result += (
                            1j ** (-l)
                            * cg_coefficients[
                                l ** 2 + l + m,
                                l1 ** 2 + l1 + m1,
                                l2 ** 2 + l2 + m2

                            ]
                            * scipy.special.spherical_yn(l, k * interatomic_vector.module)
                            * compute_real_sph_harm((l, m), interatomic_vector.phi, interatomic_vector.theta)
                        )

                result *= (-4 * np.pi * 1j ** (l1 - l2))
                matrix[i, j] = result.real
            else:
                result = 0

                for l in range(0, LMAX + 1):
                    for m in range(-l, l + 1):
                        result += (
                            cg_coefficients[
                                l ** 2 + l + m,
                                l1 ** 2 + l1 + m1,
                                l2 ** 2 + l2 + m2
                            ]
                            * modified_spherical_hankel_function(l, k * interatomic_vector.module)
                            * compute_real_sph_harm((l, m), interatomic_vector.phi, interatomic_vector.theta)
                        )

                result *= (4 * np.pi * (-1) ** (l1 + l2))
                matrix[i, j] = result.real

    determinants.append(scipy.linalg.det(matrix))

for determinant in determinants:
    print(determinant)

pyplot.plot(energies, determinants)
pyplot.show()


from django.shortcuts import render
from django.http import JsonResponse
from .models import Client

def get_all_clients(request):
    if request.method == "GET":
        clients = Client.objects.filter()
        clients_list = []
        for client in clients:
            clients_list.append({"id": client.id, "name": client.name})
        return JsonResponse(clients_list, safe=False)


import numpy as np
from numpy.typing import ArrayLike, NDArray
from typing import Literal, Tuple, Union

from ..utils._validations import _ensure_ndarray
from ..transforms.householder import house

def house_hess(
    a: ArrayLike,
    mode: Literal["full", "hess"] = "full",
    overwrite_a: bool = False
) -> Union[Tuple[NDArray[np.float64], ...], NDArray[np.float64]]:
    copy_a = not overwrite_a
    a = _ensure_ndarray(
        a,
        ensure_square=True,
        copy=copy_a,
        dtype="float64"
    )

    n = a.shape[0]
    if mode == "full":
        betas = np.zeros(n - 2)
    for i in range(n - 2):
        beta, v = house(a[i + 1:, i], 0)
        if mode == "full":
            betas[i] = beta
        a[i + 1:, i:] -= beta * np.dot(np.outer(v, v), a[i + 1:, i:])
        a[:, i + 1:] -= beta * np.dot(a[:, i + 1:], np.outer(v, v))
        if mode == "full":
            a[i + 2:, i] = v[1:n - i - 1]

    if mode == "full":
        u = np.identity(n)
        v = np.zeros(n - 1)
        for i in range(n - 3, -1, -1):
            v[i] = 1.0
            v[i + 1:] = a[i + 2:, i]
            a[i + 2:, i] = 0.0
            u[i + 1:, i + 1:] -= betas[i] * np.dot(np.outer(v[i:], v[i:]), u[i + 1:, i + 1:])

        return u, a
    elif mode == "hess":
        return a


from tensorflow.keras.models import load_model
from tensorflow.keras.preprocessing import image
import numpy as np
import os
import argparse
import csv

parser = argparse.ArgumentParser()
parser.add_argument("folder", type=str)
args = parser.parse_args()

folder_path = args.folder # image folder

# folder_path = "final/test_dir/prefix/"
model_path = 'models/model/' # model folder

img_width, img_height = 384, 128

model = load_model(model_path) # load the trained model

images = []
files = os.listdir(folder_path)
cnt = 0
for img in files:
    img = os.path.join(folder_path, img)
    img = image.load_img(img, target_size=(img_height, img_width),color_mode='grayscale')
    img = image.img_to_array(img)
    img /= 255.
    img = np.expand_dims(img, axis=0)
    images.append(img)
    cnt+=1
    if (cnt % 1000 == 0): print(cnt)

# stack up images list to pass for prediction
images = np.vstack(images)
classes = np.argmax(model.predict(images), axis=-1)
k = list(classes)
class_names = ['infix', 'postfix', 'prefix']
final = [["Image Name", "Label"]]
for i in range(len(files)):
    final.append([files[i], class_names[k[i]]])

with open("team_name_1.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(final)


import logging
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import argparse
import os

# TE Age Landscapes
# Heavily modified from 11 August 2019 script by Jenna R. Grimshaw (jenna.grimshaw@ttu.edu)
# This script will take bedfiles and reformat into separate columns as follows:
# Scaffold, TE, Size, Divergence
# Note: Divergence must be in decimal format, i.e. 1% divergence = 0.01

### Arguments
ap = argparse.ArgumentParser()
ap.add_argument("-b", "--BEDFILE", required=True, help="Please enter your bedfile")
ap.add_argument("-g", "--GENOMESIZE", required=True, type = int, help="Enter size of genome (bp)")
ap.add_argument("-t", "--TAXON", required=True, help="Enter your taxon abbreviation")
ap.add_argument("-f", "--FAMILY", required = False, help = "Choose the TE family you want to plot, e.g. 'Ves', 'MIR', 'L1', 'HAL', 'hAT', 'Helitron', 'piggyBac', 'TcMariner'")
ap.add_argument("-sf", "--SUBFAM_LIST", required = True, help = "List file of the subfamilies you want to plot")
#ap.add_argument("-sf", "--SUPERFAMILY", action = "append", default = [], required = True, help = "Choose the TE superfamily you want to plot, e.g. 'SINE', 'LINE', 'LTR', 'DNA', 'RC'")
#ap.add_argument("-s", "--SUBFAMILY", action = "append", default = [], required = True, help = "Remove false positives that do not contain THIS")
args=vars(ap.parse_args())

##############################################
################ Functions ###################
##############################################

def SUM_OF_SIZE(data, element, min, max):
	size = []
	##Proxy time conversion
	## d = r*t -> d/r = t -> div/(neutral mutation rate) = time (years)
	## div(decimal)/(neutral mut rate per year) = time(years)/1E06 = time(MY)
	## Mammalian neutral mutation rate per year = 2.22 x 10^-09 sub/year
	## So div = 0.01 is ~4.5 MY, div = 0.111 is ~50 MY; div = 0.11 is ~49.55 MY
	rate = 0.00000000222
	mil_year = 1000000
	#CONVERSION = (DIV / rate) / mil_year
	div_min = round(float(min * mil_year * rate),5)
	div_max = round(float(max * mil_year * rate), 5)
	for DIV, SIZE, TE in zip(data.Divergence, data.Size, data.TE):
		if element == TE:
			if DIV > div_min and DIV <= div_max:
				size.append(SIZE)
	return sum(size)
# This function will add up the lengths/sizes
# of TEs within a min and max Divergence
# and then will return the sum of those lengths

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

# Enter genome size
genomesize = args["GENOMESIZE"]

# Import RM_bed file
fields = ["Scaffold", "Start", "Stop", "TE", "Length", "Orientation", "Superfamily", "Family", "Divergence", "XX"]
file = pd.read_csv(args["BEDFILE"], sep="\t", names=fields)
print("original file is: ", len(file))

#Import list of TE subfamilies of interested
TELIST = []
NAME = os.path.basename(args["SUBFAM_LIST"]).split(".")[0]
with open(args["SUBFAM_LIST"], "r") as f:
	for line in f:
		line = line.strip()
		TELIST.append(line)

# We are only interested in the FAMILY given
# So create a new dataframe only using TEs from that FAMILY
# Calculate length, drop unneeded columns, reorder columns
if args["FAMILY"]:
	FAMILY = args["FAMILY"]
	if FAMILY == "TcMariner" or "Tc-Mariner" or "TcMar":
		FAMILY == 'TcMar'
		FAM_SUB = file[file.Family.str.contains(FAMILY)]
	else:
		FAM_SUB = file[file.Family == FAMILY]
else:
	FAM_SUB = pd.DataFrame(columns = fields)
	for element in TELIST:
		FAM_SUB = FAM_SUB.append(file[file.TE == element])

FAM_SUB["Size"] = FAM_SUB["Stop"] - FAM_SUB["Start"]
FAM_SUB=FAM_SUB.drop(["Start", "Stop", "Length", "Superfamily", "Orientation", "XX"], axis=1)
FAM_SUB = FAM_SUB[["Scaffold", "Size", "TE","Divergence","Family"]]
FAM_SUB["Divergence"] = FAM_SUB["Divergence"]/100
#print("TE family {} dataframe is: {}".format(FAMILY, len(FAM_SUB)))
print(FAM_SUB.head())

# Remove false positives by only keeping elements that contain "SUBFAMILY"
print("Unique subfamily list:", FAM_SUB["TE"].unique())

# Find unique families
#TELIST = subfamily["TE"].unique()
#TELIST = FAM_SUB["TE"].unique()
print("TE list:", TELIST)

# Create dataframe to be used in loopfile
# I want one column with ranges in increments of millions of years (MY)
# Starting at 1 to 50 by increments of 1
loopfile = pd.DataFrame(columns = TELIST)
my_list = []

for i in range(51):
	my_list.append(i)

loopfile["Range"] = my_list

for TE in TELIST:
	min = 0
	data = []
	for year in loopfile.Range:
		sizesum = SUM_OF_SIZE(FAM_SUB, TE, float(year-1), year)
		data.append(sizesum/genomesize)
	#append TE subfamily data to loopfile
	loopfile[TE] = data
	#print(loopfile)
loopfile.to_csv(args["TAXON"]+"_"+NAME+"_ages.csv", index = False)

for TE in TELIST:
	plt.plot("Range", TE, data = loopfile)
plt.ylabel("Proportion of Genome")
plt.xlabel("Approximate Age (MY)")
##add size parameter to normalize y-axis
#plt.legend()
plt.legend(loc=1)
#plt.show()
plt.savefig(args["TAXON"]+"_"+NAME+".png")


#imports the sqlite3 module, allowing use of its classes and methods
import sqlite3

#establishes the connection and sets it to variable 'connection', if there is no "Test_database.db"
#it will be created and the connection will be established
connection = sqlite3.connect("C:/Choose_your_file_path_here_where_you_want/Test_database.db")

'''
communicates across the connection
this line instatiates a cursor object
A cursor is a control structure that enables operations on a database.
Our cursor object 'c' will let us execute commands on our SQL database 'Test_database'
and return the results
'''
c = connection.cursor()

'''
This line creates a new table named People and inserts three new columns into the table:
text for storing each person's FirstName, another text field to store the LastName
and an integer to store Age
'''
c.execute("CREATE TABLE People(FirstName TEXT, LastName TEXT, Age INT)")

'''
Inserts data into the new table "People"
A new row with the FirstName of Ron, a LastName of Obvious, and an Age equal to 42.
the following line commits the change we made to the table to say that we really
meant to change the table's contents - otherwise our change wouldn't actually be saved.
'''
c.execute("INSERT INTO People VALUES('Ron', 'Obvious', 42)")
connection.commit()

'''
one-time-use databases can also be created using the line of code below.
It allows the programmer to test code or play around with table structures,
the special name is :memory: for you database to create it in temporary RAM
'''
connection = sqlite3.connect(':memory:')

#to delete the People table we use the DROP TABLE statement: i.e: below
#the SQL command "IF EXISTS" checked if the table exists before trying to drop it, usually a good idea
#helps in avoiding errors that would occur if we happeend to try deleting a table that's
#already been deleted or never existed
c.execute("DROP TABLE IF EXISTS People")

'''
Once done with a db connection, we need to close() the connection.
Just like closing files, this pushes any changes out ot the database and frees up any
resources currently in memory that are no longer needed.
You close the db connection in the same way as you close files.
'''
connection.close()

'''
When working with db connection, it's also a good idea to use the "with" keyword to simplify your
code (and your llife), similar hto how we have used 'with' to open files.
To run more than one line of SQL code at a time, there are a couple possible options.
A simple option is to use the executescript() method and give it a string that represents a full script;
although lines of SWL code will be seperated by semicolons, it is common to pass multi-line string for readabiltiy.
'''
with sqlite3.connect("test_database.db") as connection:
    #perform any SQL operations using connection here
    c = connection.cursor()
    c.executescript("""DROP TABLE IF EXISTS People;
                    CREATE TABLE People(FirstName TEXT, LastName TEXT, Age INT);
                    INSERT INTO People VALUES('Ron', 'Obvious', '42');
                    """)

'''
another way to execute many similar statements by using the executemany() method and supplying
a tuple of tuples where each inner tuple suppplies the information for a single command.
For instance, if we have a lot of people's information to insert into our People table, we could
save this information in the following tuple of tuples
'''
peopleValues = (('Ron', 'Obious', 42), ('Luigi', 'Vercotti', 43), ('Arthur', 'Belling', 28))

'''
Then the following comman will insert all of these people at once (after preparing our connection and our People table)
by using the single line.
The question marks act as place-holders for the tuples in peopleValues.
This is called a parameterized statement.
The difference between parameterized and non-parameterized code is very similar to how
we can write out strings by concatenating many parts together versus using the strin format() method to insert
specific piecs into a string after creating it.
'''
c.executemany("INSERT INTO People VALUES(?,?,?)", peopleValues)