import random

from flask import Blueprint, render_template, request, \
    redirect, url_for
from sqlalchemy import desc, asc, and_, not_, or_
from flask_restful import Resource

from app.models import db, Student, Grade, Course
from utils import api

blue = Blueprint('app', __name__)

@blue.route('/')
def hello():
    return 'hello'

@blue.route('create_db/')
def create_db():
    # 创建数据中的表
    db.create_all()
    return '创建数据表成功'

@blue.route('drop_db/')
def drop_db():
    # 删除数据中的表
    db.drop_all()
    return '删除数据表成功'

@blue.route('create_stu/')
def create_stu():
    # 创建学生信息
    stu = Student()
    stu.s_name = '小明1'
    stu.s_age = 18
    # # 第一种：直接保存数据
    # db.session.add(stu)
    # # 事务：完整，一致，持久，原子
    # db.session.commit()

    # 第二种：自定义save()方法
    stu.save()
    return '创建学生信息成功'

@blue.route('sel_stu/')
def sel_stu():
    # 查询所有操作
    students = Student.query.all()
    # 第一种方式：查询id=1的学生信息
    students = Student.query.filter(Student.id==1)
    # 第二种方式：查询id=1的学生信息
    students = Student.query.filter_by(id=1)
    # 第三种方式：查询id=1的学生信息
    sql = 'select * from student where id=1;'
    students = db.session.execute(sql)
    # 查询所有学生数据
    sql = 'select * from student;'
    students = db.session.execute(sql)

    # 模糊查询, 查询姓名中包含妲己的学生信息
    # 在django中 filter(s_name__contains='妲己')
    # 语法：filter(模型名.属性.运算符('xx'))
    students = Student.query.filter(Student.s_name.contains('妲己'))
    # 以什么开始，startswith
    students = Student.query.filter(Student.s_name.startswith('校'))
    # 以什么结束，endswith
    students = Student.query.filter(Student.s_name.endswith('9'))
    # 查询年龄大于等于16的学生信息
    students = Student.query.filter(Student.s_age.__ge__(16))
    # 查询id在10到12之间的学生信息
    students = Student.query.filter(Student.id.in_([10,11,12]))
    # 查询年龄小于15的学生信息
    students = Student.query.filter(Student.s_age.__lt__(15))
    # 模糊查询，使用like，查询姓名中第二位为花的学生信息
    # like '_花%'
    students = Student.query.filter(Student.s_name.like('_花%'))
    # 按照id降序,升序
    students = Student.query.order_by('id')
    students = Student.query.order_by('-id')

    students = Student.query.order_by(desc('id'))
    students = Student.query.order_by(asc('id'))

    students = Student.query.order_by('id desc')
    students = Student.query.order_by('id asc')

    # 查询数据，获取第五个到第十个的数据
    students = Student.query.all()[4:10]
    page = 3
    students = Student.query.offset((page-1) * 2).limit(2)
    # 使用get，获取id=1的学生信息
    # get拿不到值，不会报错，只会返回一个空
    students = Student.query.get(1)

    # and_, not_, or_
    students = Student.query.filter(Student.s_age==16,
                                    Student.s_name.contains('花'))

    students = Student.query.filter(and_(Student.s_age==16,
                                         Student.s_name.contains('花')))
    students = Student.query.filter(not_(Student.s_age == 16),
                                    not_(Student.s_name.contains('花')))

    students = Student.query.filter(or_(Student.s_age == 16,
                                         Student.s_name.contains('花')))

    # 查询年龄小于15的学生信息
    students = Student.query.filter(Student.s_age < 15)
    students = Student.query.filter(Student.s_age.__lt__(15))

    return render_template('stus.html', stus=students)

@blue.route('del_stu/<int:id>/', methods=['GET'])
def del_stu(id):
    # 删除学生
    if request.method == 'GET':
        stu = Student.query.filter(Student.id==id).first()
        db.session.delete(stu)
        db.session.commit()
        return '删除学生成功'

@blue.route('edit_stu/<int:id>/', methods=['GET', 'POST'])
def edit_stu(id):
    if request.method == 'GET':
        stu = Student.query.filter_by(id=id).first()
        return render_template('edit.html', stu=stu)
    if request.method == 'POST':
        username = request.form.get('username')
        age = request.form.get('age')
        # 更新,第一种
        # stu = Student.query.filter_by(id=id).first()
        # stu.s_name = username
        # stu.s_age = age
        # stu.save()
        # 更新第二种
        Student.query.filter_by(id=id).update({'s_name': username, 's_age': age})
        db.session.commit()

        return redirect(url_for('app.sel_stu'))

@blue.route('create_many_stu/', methods=['GET'])
def create_many_stu():
    if request.method == 'GET':
        # 批量添加学生信息
        stus_list = []
        for i in range(10):
            stu = Student()
            stu.s_name = '校花%s' % random.randrange(10,10000)
            stu.s_age = 16
            stus_list.append(stu)
        # add_all()添加学生信息，参数为列表，列表中为添加的学生对象
        db.session.add_all(stus_list)
            # db.session.add(stu)
        db.session.commit()
        return '批量创建'

@blue.route('create_many_stu_init/', methods=['GET'])
def create_many_stu_init():
    if request.method == 'GET':
        stu_list = []
        for i in range(10):
            stu = Student('小花%s' % random.randrange(10,10000), 10)
            stu_list.append(stu)
        db.session.add_all(stu_list)
        db.session.commit()
        return '批量创建成功'

@blue.route('paginate/', methods=['GET'])
def stu_paginate():
    # 实现分页
    # 1. 使用offset+limit实现
    page = int(request.args.get('page', 1))
    stus = Student.query.offset((page - 1)*5).limit(5)
    # 2. 使用切片实现
    stus = Student.query.all()[(page - 1)*5:page*5]
    # 3. 使用paginate实现
    paginate = Student.query.paginate(page, 10)
    stus = paginate.items
    return render_template('stus.html', stus=stus, paginate=paginate)

# 创建班级， add()， add_all()
@blue.route('create_grade/', methods=['GET'])
def create_grade():
    grade_name = ['Python', 'Java', 'Php', 'VHDL']
    g_list = []
    for name in grade_name:
        grade = Grade()
        grade.g_name = name
        g_list.append(grade)
        # db.session.add(grade)
        # db.session.commit()
    db.session.add_all(g_list)
    db.session.commit()

    return '创建班级成功'

# 添加班级和学生信息关联关系

@blue.route('sel_grade_by_stu/', methods=['GET'])
def sel_grade_by_stu():
    if request.method == 'GET':
        # 查询id=4的学生，对应的班级
        # 1. 获取id=4的学生信息
        stu = Student.query.get(4)
        # 2. 使用关联关系，relationship中的backref去反向查询班级信息
        grade = stu.stu
        return 'id为%s的学生的班级为：%s' % (4, grade.g_name)

@blue.route('sel_stu_by_grade/', methods=['GET'])
def sel_stu_by_grade():
    if request.method == 'GET':
        # 查询java班中的学生信息
        grade = Grade.query.filter(Grade.g_name=='Java').first()
        # 班级对象.relationship的字段
        students = grade.student
        return '查询成功'

# 添加课程信息
@blue.route('add_course/', methods=['GET'])
def add_course():
    if request.method == 'GET':
        courses = ['线代', '高数', '大学物理', '计算机', '英语']
        for course in courses:
            c = Course()
            c.c_name = course
            db.session.add(c)
        db.session.commit()
        return '创建课程成功'

@blue.route('add_stu_course/', methods=['GET'])
def add_stu_course():
    if request.method == 'GET':
        # id=4的学生选择了三门课程(id=1,2,3)
        stu = Student.query.get(4)
        c1 = Course.query.get(1)
        c2 = Course.query.get(2)
        c3 = Course.query.get(3)
        stu.cou.append(c1)
        stu.cou.append(c2)
        stu.cou.append(c3)
        db.session.add(stu)
        db.session.commit()
        return '添加学生的课程成功'

@blue.route('del_stu_course/', methods=['GET'])
def del_stu_course():
    if request.method == 'GET':
        stu = Student.query.get(4)
        cou = Course.query.get(1)
        # 删除列表中数据
        stu.cou.remove(cou)
        # del stu.cou[0]
        db.session.add(stu)
        db.session.commit()
        return '删除学生的课程成功'

class StudentResource(Resource):

    def get(self, id):
        stu = Student.query.get(id)
        return {'s_name': stu.s_name, 's_age': stu.s_age}

    def post(self, id):
        pass

    def put(self):
        pass

    def patch(self, id):
        s_name = request.form.get('s_name')
        stu = Student.query.get(id)
        stu.s_name = s_name
        db.session.add(stu)
        db.session.commit()
        return {'code': 200, 'msg': '请求成功'}

    def delete(self):
        pass

api.add_resource(StudentResource, '/api/student/<int:id>/')


import os
import argparse
import json
import pickle
import random
from datetime import date

import numpy as np

import torch

from torch.utils.data import DataLoader, random_split, ConcatDataset
from torch.optim import SGD, Adam
from torch.nn.functional import binary_cross_entropy, pad, one_hot
from sklearn import metrics
from data_loaders.assist2009 import ASSIST2009
from data_loaders.assist2012 import ASSIST2012
from data_loaders.ednet01 import EdNet01
from data_loaders.csedm import CSEDM

# 모델 추가
from models.dkt_sc import DKT_FUSION as DKT_F
from models.dkt_rear import DKT as DKT_REAR
from models.dkt_front import DKT as DKT_FRONT
from models.dkt import DKT
from models.dkvmn import DKVMN
from models.dkvmn_text import SUBJ_DKVMN
from models.dkvmn_back import BACK_DKVMN
from models.sakt import SAKT
from models.sakt_front import SAKT as SAKT_FRONT
from models.sakt_rear import SAKT as SAKT_REAR
from models.saint import SAINT
from models.saint_front import SAINT as SAINT_FRONT
from models.saint_rear import SAINT as SAINT_REAR
from models.auto import AUTO
from models.mekt import MEKT
from models.dirt import DeepIRT
from models.qakt import QAKT
from models.akt import AKT

# 모델에 따른 train
from models.dkt_sc import dkt_train as dkf_train
from models.dkt_rear import dkt_train as dk_rear_train
from models.dkt_front import dkt_train as dk_front_train
from models.dkt import train_model as dkt_train
from models.auto import auto_train
from models.dkvmn_text import train_model as plus_train
from models.dkvmn_back import train_model as minus_train
from models.sakt import train_model as sakt_train
from models.sakt_front import sakt_train as sakt_front_train
from models.sakt_rear import sakt_train as sakt_rear_train
from models.dkvmn import train_model as dkvmn_train
from models.saint import train_model as saint_train
from models.saint_front import train_model as saint_front_train
from models.saint_rear import train_model as saint_rear_train
from models.akt import train_model as akt_train

# 모델에 따른 test
from models.dkt import test_model as dkt_test
from models.dkvmn import test_model as dkvmn_test
from models.sakt import test_model as sakt_test
from models.saint import test_model as saint_test
from models.akt import test_model as akt_test

from models.utils import collate_fn, collate_ednet, cal_acc_class, reset_weight

# Cross Validation
from sklearn.model_selection import KFold

# wandb
import wandb

# seed 고정
seed = 13
#deterministic = True

random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
#if deterministic:
    #torch.backends.cudnn.deterministic = True
    #torch.backends.cudnn.benchmark = False

# Train function
def train_model(model, train_loader, valid_loader, num_q, num_epochs, opt, ckpt_path, mode=0, use_wandb=False):
    max_auc = 0
    loss_means = []
    aucs = []
    accs = []
    precisions = []
    recalls = []
    f1s = []

    for epoch in range(0, num_epochs):
        auc_mean = []
        loss_mean = []
        acc_mean = []
        model.train()
        for i, data in enumerate(train_loader, 0):
            # q_seqs, r_seqs, qshft_seqs, rshft_seqs, mask_seqs, bert_sentences, bert_sentence_types, bert_sentence_att_mask, proc_atshft_sentences
            q, r, qshft_seqs, rshft_seqs, m, bert_s, bert_t, bert_m, q2diff_seqs, pid_seqs, pidshift, hint_seqs = data

            # 현재 답안 예측
            inpt_q = q.long()
            pred_t = r
            if mode == 1: # 다음 답안 예측
                inpt_q = qshft_seqs.long()
                pred_t = rshft_seqs
            elif mode == 2: # 스코어 예측
                pred_t = pid_seqs
            elif mode == 3: # 다음 스코어 예측
                inpt_q = qshft_seqs.long()
                pred_t = pidshift

            # 현재까지의 입력을 받은 뒤 다음 문제 예측
            y, Mv = model(q.long(), r.long()) # sakt는 qshft_seqs.long() 추가
            # y = (y * one_hot(inpt_q, num_q)).sum(-1)

            opt.zero_grad()
            y = torch.masked_select(y, m)
            t = torch.masked_select(pred_t, m) # rshft 대신 pidshift
            h = torch.masked_select(hint_seqs, m)

            loss = binary_cross_entropy(y, t)
            loss.backward()
            opt.step()

            loss_mean.append(loss.detach().cpu().numpy())
            auc_mean.append(metrics.roc_auc_score(
                y_true=t.detach().cpu().numpy(), y_score=y.detach().cpu().numpy()
            ))
            bin_y = [1 if p >= 0.5 else 0 for p in y.detach().cpu().numpy()]
            acc_mean.append(metrics.accuracy_score(t.detach().cpu().numpy(), bin_y))

        loss_mean = np.mean(loss_mean)
        auc_mean = np.mean(auc_mean)
        acc_mean = np.mean(acc_mean)

        if(use_wandb != False):
            wandb.log(
            {
                "epoch": epoch,
                "train_auc": auc_mean,
                "train_acc": acc_mean,
                "train_loss": loss_mean
            })

        print(f"[Train] Epoch: {epoch}, AUC: {auc_mean}, acc: {acc_mean}, Loss Mean: {np.mean(loss_mean)}")

        with torch.no_grad():
            model.eval()
            auc_mean = []
            loss_mean = []
            acc_mean = []
            precision_mean = []
            recall_mean = []
            f1_mean = []

            best_loss = 10 ** 9
            patience_limit = 3
            patience_check = 0

            for i, data in enumerate(valid_loader):
                q, r, qshft_seqs, rshft_seqs, m, bert_s, bert_t, bert_m, q2diff_seqs, pid_seqs, pidshift, hint_seqs = data

                # 현재 답안 예측
                inpt_q = q.long()
                pred_t = r
                if mode == 1: # 다음 답안 예측
                    inpt_q = qshft_seqs.long()
                    pred_t = rshft_seqs
                elif mode == 2: # 스코어 예측
                    pred_t = pid_seqs
                elif mode == 3: # 다음 스코어 예측
                    inpt_q = qshft_seqs.long()
                    pred_t = pidshift

                y, Mv = model(q.long(), r.long()) # sakt는 qshft_seqs.long() 추가
                # y = (y * one_hot(inpt_q, num_q)).sum(-1)

                # y와 t 변수에 있는 행렬들에서 마스킹이 true로 된 값들만 불러옴
                q = torch.masked_select(inpt_q, m).detach().cpu()
                y = torch.masked_select(y, m).detach().cpu()
                t = torch.masked_select(pred_t, m).detach().cpu()
                h = torch.masked_select(hint_seqs, m).detach().cpu()

                auc = metrics.roc_auc_score(
                    y_true=t.numpy(), y_score=y.numpy()
                )
                auc_mean.append(auc)

                bin_y = [1 if p >= 0.5 else 0 for p in y.detach().cpu().numpy()]
                acc = metrics.accuracy_score(t.detach().cpu().numpy(), bin_y)
                precision = metrics.precision_score(t.numpy(), bin_y, average='binary')
                recall = metrics.recall_score(t.numpy(), bin_y, average='binary')
                f1 = metrics.f1_score(t.numpy(), bin_y, average='binary')
                q_accs, cnt = cal_acc_class(q.long(), t.long(), bin_y)

                acc_mean.append(acc)
                precision_mean.append(precision)
                recall_mean.append(recall)
                f1_mean.append(f1)

                loss = binary_cross_entropy(y, t)
                loss_mean.append(loss)

                if loss > best_loss:
                    patience_check += 1

                    if patience_check >= patience_limit:
                        break
                else:
                    best_loss = loss
                    patience_check = 0

                if auc > max_auc :
                    torch.save(
                        model.state_dict(),
                        os.path.join(
                            ckpt_path, "model.ckpt"
                        )
                    )
                    max_auc = auc
                    with open(os.path.join(ckpt_path, f"best_val_auc.pkl"), "wb") as f:
                        best_pef = {"seed": wandb.config.seed, \
                                    "dropout": wandb.config.dropout, \
                                    "lr": wandb.config.learning_rate, \
                                    'dim_s': {'values': [20, 50]}, \
                                    'size_m': {'values': [20, 50]}
                                    # "emb_size": wandb.config.emb_size, \
                                    # "hidden_size": wandb.config.hidden_size \
                                    }
                        pickle.dump(best_pef, f)

            loss_mean = np.mean(loss_mean)
            auc_mean = np.mean(auc_mean)
            acc_mean = np.mean(acc_mean)
            precision_mean = np.mean(precision_mean)
            recall_mean = np.mean(recall_mean)
            f1_mean = np.mean(f1_mean)

            if(use_wandb != False):
                wandb.log(
                {
                    "epoch": epoch,
                    "val_auc": auc_mean,
                    "val_acc": acc_mean,
                    "val_loss": loss_mean
                })

            aucs.append(auc_mean)
            loss_means.append(loss_mean)
            accs.append(acc_mean)
            precisions.append(precision_mean)
            recalls.append(recall_mean)
            f1s.append(f1_mean)
            print(f"[Valid] Epoch: {epoch} Result: AUC: {auc_mean}, ACC: {acc_mean}, loss: {loss_mean}")

        print(f"========== Finished Epoch: {epoch} ============")

    return aucs, loss_means, accs, q_accs, cnt, precisions, recalls, f1s

# Test function
def test_model(model, test_loader, num_q, ckpt_path, mode=0, use_wandb=False):

    if(use_wandb != False):
        wandb.init(group=f"test_{date.today().isoformat()}_{mode}", name=f"{mode}", reinit=True)

    # 실제 성능측정, mode 0은 현재 답안 예측, 1은 다음 답안 예측, 2는 스코어 예측
    model.load_state_dict(torch.load(os.path.join(ckpt_path, "model.ckpt")))
    loss_mean = []
    aucs = []
    accs = []
    precisions = []
    recalls = []
    f1s = []

    with torch.no_grad():
        for i, data in enumerate(test_loader, 0):
            q, r, qshft_seqs, rshft_seqs, m, bert_s, bert_t, bert_m, q2diff_seqs, pid_seqs, pidshift, hint_seqs = data

            # 현재 답안 예측
            inpt_q = q.long()
            pred_t = r
            if mode == 1: # 다음 답안 예측
                inpt_q = qshft_seqs.long()
                pred_t = rshft_seqs
            elif mode == 2: # 스코어 예측
                pred_t = pid_seqs
            elif mode == 3: # 다음 스코어 예측
                inpt_q = qshft_seqs.long()
                pred_t = pidshift

            model.eval()
            y, Mv = model(q.long(), r.long())
            # y = (y * one_hot(inpt_q, num_q)).sum(-1)

            # y와 t 변수에 있는 행렬들에서 마스킹이 true로 된 값들만 불러옴
            q = torch.masked_select(inpt_q, m).detach().cpu()
            y = torch.masked_select(y, m).detach().cpu()
            t = torch.masked_select(pred_t, m).detach().cpu()
            h = torch.masked_select(hint_seqs, m).detach().cpu()

            auc = metrics.roc_auc_score(
                y_true=t.numpy(), y_score=y.numpy()
            )
            bin_y = [1 if p >= 0.5 else 0 for p in y.detach().cpu().numpy()]
            acc = metrics.accuracy_score(t.detach().cpu().numpy(), bin_y)
            precision = metrics.precision_score(t.numpy(), bin_y, average='binary')
            recall = metrics.recall_score(t.numpy(), bin_y, average='binary')
            f1 = metrics.f1_score(t.numpy(), bin_y, average='binary')

            loss = binary_cross_entropy(y, t)

            print(f"[Test] number: {i}, AUC: {auc}, ACC: {acc}, loss: {loss}")

            aucs.append(auc)
            loss_mean.append(loss)
            accs.append(acc)
            q_accs, cnt = cal_acc_class(q.long(), t.long(), bin_y)
            precisions.append(precision)
            recalls.append(recall)
            f1s.append(f1)

        loss_means = np.mean(loss_mean) # 실제 로스 평균값을 구함
        auc_mean = np.mean(aucs)
        acc_mean = np.mean(accs)
        f1_mean = np.mean(f1s)

        if(use_wandb != False):
            wandb.log(
            {
                "test_auc": auc_mean,
                "test_acc": acc_mean,
                "test_loss": loss_mean
            })
            wandb.finish()

        print(f"[Total Test]: AUC: {auc_mean}, ACC: {acc_mean}, F1 Score: {f1_mean} ")

    return aucs, loss_means, accs, q_accs, cnt, precisions, recalls, f1s

# main program
def main(model_name, dataset_name, use_wandb):
    KAKAO_CKPTS = "/app/outputs/"
    # KAKAO_CKPTS = "./"
    if not os.path.isdir(f"{KAKAO_CKPTS}ckpts"): # original: ckpts
        os.mkdir(f"{KAKAO_CKPTS}ckpts")
    ckpt_path = os.path.join(f"{KAKAO_CKPTS}ckpts", model_name)
    if not os.path.isdir(ckpt_path):
        os.mkdir(ckpt_path)

    ckpt_path = os.path.join(ckpt_path, dataset_name)
    if not os.path.isdir(ckpt_path):
        os.mkdir(ckpt_path)

    with open("config.json") as f:
        config = json.load(f)
        model_config = config[model_name]
        train_config = config["train_config"]

    with open("wandb_config.json") as f:
        wandb_config = json.load(f)
        WANDB_API_KEY = wandb_config['wandb_api_key']

    batch_size = train_config["batch_size"]
    num_epochs = train_config["num_epochs"]
    train_ratio = train_config["train_ratio"]
    learning_rate = train_config["learning_rate"]
    optimizer = train_config["optimizer"] # can be sgd, adam
    seq_len = train_config["seq_len"] # 샘플링 할 갯수

    # 데이터셋 추가 가능
    collate_pt = collate_fn
    if dataset_name == "ASSIST2009":
        dataset = ASSIST2009(seq_len)
    elif dataset_name == "ASSIST2012":
        dataset = ASSIST2012(seq_len)
    elif dataset_name == "EDNET01":
        dataset = EdNet01(seq_len)
        collate_pt = collate_ednet
    elif dataset_name == "CSEDM":
        dataset = CSEDM(seq_len)

    if torch.cuda.is_available():
        device = "cuda"
    else:
        device = "cpu"

    # JSON으로 설정값 저장
    with open(os.path.join(ckpt_path, "model_config.json"), "w") as f:
        json.dump(model_config, f, indent=4)
    with open(os.path.join(ckpt_path, "train_config.json"), "w") as f:
        json.dump(train_config, f, indent=4)

    ## 가변 벡터이므로 **
    train_model = None
    test_model = None
    if model_name == "dkt":
        model = torch.nn.DataParallel(DKT(dataset.num_q, **model_config)).to(device)
        train_model = dkt_train
        test_model = dkt_test
    elif model_name == "dkf":
        model = torch.nn.DataParallel(DKT_F(dataset.num_q, **model_config)).to(device)
    elif model_name == "dkt-":
        model = torch.nn.DataParallel(DKT_FRONT(dataset.num_q, **model_config)).to(device)
    elif model_name == "dkt+":
        model = torch.nn.DataParallel(DKT_REAR(dataset.num_q, **model_config)).to(device)
    elif model_name == 'dkvmn':
        model = torch.nn.DataParallel(DKVMN(dataset.num_q, **model_config)).to(device)
        train_model = dkvmn_train
        test_model = dkvmn_test
    elif model_name == 'dkvmn+':
        model = torch.nn.DataParallel(SUBJ_DKVMN(dataset.num_q, num_qid=dataset.num_pid, **model_config)).to(device)
    elif model_name == 'dkvmn-':
        model = torch.nn.DataParallel(BACK_DKVMN(dataset.num_q, **model_config)).to(device)
    elif model_name == 'sakt':
        model = torch.nn.DataParallel(SAKT(dataset.num_q, **model_config)).to(device)
        train_model = sakt_train
        test_model = sakt_test
    elif model_name == 'sakt-':
        model = torch.nn.DataParallel(SAKT_FRONT(dataset.num_q, **model_config)).to(device)
    elif model_name == 'sakt+':
        model = torch.nn.DataParallel(SAKT_REAR(dataset.num_q, **model_config)).to(device)
    elif model_name == 'saint':
        model = torch.nn.DataParallel(SAINT(dataset.num_q, **model_config)).to(device)
        train_model = saint_train
        test_model = saint_test
    elif model_name == 'saint-':
        model = torch.nn.DataParallel(SAINT_FRONT(dataset.num_q, **model_config)).to(device)
    elif model_name == "saint+":
        model = torch.nn.DataParallel(SAINT_REAR(dataset.num_q, **model_config)).to(device)
    elif model_name == 'akt':
        model = torch.nn.DataParallel(AKT(n_question=dataset.num_q, n_pid=dataset.num_pid, **model_config)).to(device)
        train_model = akt_train
        test_model = akt_test
    elif model_name == "auto":
        model = torch.nn.DataParallel(AUTO(num_q=dataset.num_q, **model_config)).to(device)
    elif model_name == "mekt":
        model = MEKT(dataset.num_q, **model_config).to(device)
    elif model_name == "dirt":
        model = DeepIRT(dataset.num_q, dataset.num_u, **model_config).to(device)
    elif model_name == "qakt":
        model = QAKT(dataset.num_q, **model_config).to(device)

    else:
        print(f"The wrong model name was used...: {model_name}")
        return

    # 데이터셋 분할
    data_size = len(dataset)
    train_size = int(data_size * train_ratio)
    valid_size = int(data_size * ((1.0 - train_ratio) / 2.0))
    test_size = data_size - train_size - valid_size

    train_dataset, valid_dataset, test_dataset = random_split(
        dataset, [train_size, valid_size, test_size], generator=torch.Generator(device=device)
    )

    # 연결
    tv_dataset = ConcatDataset([train_dataset, valid_dataset])

    # pickle에 얼마만큼 분할했는지 저장
    if os.path.exists(os.path.join(dataset.dataset_dir, "train_indices.pkl")):
        with open(
            os.path.join(dataset.dataset_dir, "train_indices.pkl"), "rb"
        ) as f:
            train_dataset.indices = pickle.load(f)
        with open(
            os.path.join(dataset.dataset_dir, "valid_indicies.pkl"), "rb"
        ) as f:
            valid_dataset.indices = pickle.load(f)
        with open(
            os.path.join(dataset.dataset_dir, "test_indices.pkl"), "rb"
        ) as f:
            test_dataset.indices = pickle.load(f)
    else:
        with open(
            os.path.join(dataset.dataset_dir, "train_indices.pkl"), "wb"
        ) as f:
            pickle.dump(train_dataset.indices, f)
        with open(
            os.path.join(dataset.dataset_dir, "valid_indicies.pkl"), "wb"
        ) as f:
            pickle.dump(valid_dataset.indices, f)
        with open(
            os.path.join(dataset.dataset_dir, "test_indices.pkl"), "wb"
        ) as f:
            pickle.dump(test_dataset.indices, f)

    if optimizer == "sgd":
        opt = SGD(model.parameters(), learning_rate, momentum=0.9)
    elif optimizer == "adam":
        opt = Adam(model.parameters(), learning_rate)
    lr_scheduler = torch.optim.lr_scheduler.ExponentialLR(opt, gamma=0.5)
    opt.lr_scheduler = lr_scheduler

    # 현재꺼 예측, 다음꺼 예측, CSEDM 현재꺼 예측, 다음꺼 예측 이렇게 4개로 디자인
    pred_next = ["dkt", "dkt+", "dkt-", "sakt", "sakt+", "sakt-"]
    pred_now  = ["dkvmn", "dkvmn+", "dkvmn-", "akt", "saint", "saint+", "saint-"]

    mode = 0
    if model_name in pred_next:
        mode = 1
    elif model_name in pred_now and dataset_name == "CSEDM":
        mode = 2
    elif model_name in pred_next and dataset_name == "CSEDM":
        mode = 3

    # IIFE 즉시 실행 함수로 패킹해서 wandb로 넘겨줌
    def train_main():
        proj_name = f"{model_name}_{dataset_name}"
        num_epochs = train_config["num_epochs"]
        kfold = KFold(n_splits=5, shuffle=True)

        for fold, (train_ids, valid_ids) in enumerate(kfold.split(tv_dataset)):
            fold += 1
            print(f"========={fold}==========")
            model.apply(reset_weight)

            cv_name = f"{wandb.util.generate_id()}"
            run_name = f"{date.today().isoformat()}-{cv_name}-{fold:02}-runs"
            run = wandb.init(group=f"cv_{cv_name}_{fold}", name=run_name, reinit=True)

            seed = wandb.config.seed
            random.seed(seed)
            np.random.seed(seed)
            torch.manual_seed(seed)
            torch.cuda.manual_seed_all(seed)

            assert run is not None
            assert type(run) is wandb.sdk.wandb_run.Run
            wandb.summary["cv_fold"] = fold
            wandb.summary["num_cv_folds"] = kfold.n_splits
            wandb.summary["cv_random_state"] = kfold.random_state

            num_epochs = wandb.config.epochs
            opt.param_groups[0]['lr'] = wandb.config.learning_rate

            # 모델 파라미터
            # model.hidden_size = wandb.config.hidden_size
            model.dropout = wandb.config.dropout

            # Sample elements randomly from a given list of ids, no replacement.
            train_subsampler = torch.utils.data.SubsetRandomSampler(train_ids)
            valid_subsampler = torch.utils.data.SubsetRandomSampler(valid_ids)

            # Loader에 데이터 적재
            train_loader = DataLoader(
                tv_dataset, batch_size=batch_size,
                collate_fn=collate_pt, generator=torch.Generator(device=device),
                sampler=train_subsampler
            )
            valid_loader = DataLoader(
                tv_dataset, batch_size=batch_size,
                collate_fn=collate_pt, generator=torch.Generator(device=device),
                sampler=valid_subsampler
            )

            # 모델에서 미리 정의한 함수로 AUCS와 LOSS 계산
            # auc, loss_mean, acc, q_acc, q_cnt, precision, recall, f1 = \
            aucs, loss_means, accs, q_accs, cnt, precisions, recalls, f1s = train_model(
                model, train_loader, valid_loader, dataset.num_q, num_epochs, opt, ckpt_path, mode, use_wandb
            )

            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_aucs_{seed}.pkl"), "wb") as f:
                pickle.dump(aucs, f)
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_loss_means_{seed}.pkl"), "wb") as f:
                pickle.dump(loss_means, f)
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_accs_{seed}.pkl"), "wb") as f:
                pickle.dump(accs, f)
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_q_accs_{seed}.pkl"), "wb") as f:
                pickle.dump(q_accs, f)
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_q_cnts_{seed}.pkl"), "wb") as f:
                pickle.dump(cnt, f)
            # precisions, recalls, f1s
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_precisions_{seed}.pkl"), "wb") as f:
                pickle.dump(precisions, f)
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_recalls_{seed}.pkl"), "wb") as f:
                pickle.dump(recalls, f)
            with open(os.path.join(ckpt_path, f"{fold}_{seq_len}_f1s_{seed}.pkl"), "wb") as f:
                pickle.dump(f1s, f)

            wandb.finish()

            # DKT나 다른 모델 학습용
            # aucs, loss_means = model.train_model(train_loader, test_loader, num_epochs, opt, ckpt_path)

    if use_wandb == True:
        # wandb setting
        os.environ['WANDB_API_KEY'] = WANDB_API_KEY
        proj_name = f"{model_name}_{dataset_name}"

        # sweep config // optimization을 위한
        sweep_config = {
            'method': 'grid',
            'name': f'DKT-{model_name}',
            'metric': {
                'name': 'val_auc',
                'goal': 'maximize'
            },
            'parameters': {
                'epochs': {'values': [300]},
                'seed': {'values': [13, 42]},
                'dropout': {'values': [0, 0.05, 0.1, 0.15, 0.2, 0.25]},
                'learning_rate': {'values': [1e-3, 1e-4]},
                # 'dim_s': {'values': [20, 50]},
                # 'size_m': {'values': [20, 50]}
                # 'emb_size': {'values': [256, 512]},
                'hidden_size': {'values': [256, 512]}
            }
        }

        sweep_id = wandb.sweep(sweep=sweep_config, project=proj_name)
        wandb.agent(sweep_id, function=train_main, project=proj_name)
    else:
        train_loader = DataLoader(
            train_dataset, batch_size=batch_size,
            collate_fn=collate_pt, generator=torch.Generator(device=device)
        )
        valid_loader = DataLoader(
            valid_dataset, batch_size=batch_size,
            collate_fn=collate_pt, generator=torch.Generator(device=device)
        )
        train_model(
            model, train_loader, valid_loader, dataset.num_q, num_epochs, opt, ckpt_path, mode, use_wandb
        )

    # 마지막 테스트
    test_loader = DataLoader(
    test_dataset, batch_size=batch_size,
    collate_fn=collate_pt, generator=torch.Generator(device=device),
    )

    auc, loss_mean, acc, q_acc, q_cnt, precision, recall, f1 = \
    test_model(
        model, test_loader, dataset.num_q, ckpt_path, mode, use_wandb
    )

    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_aucs_{seed}.pkl"), "wb") as f:
        pickle.dump(auc, f)
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_loss_means_{seed}.pkl"), "wb") as f:
        pickle.dump(loss_mean, f)
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_accs_{seed}.pkl"), "wb") as f:
        pickle.dump(acc, f)
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_q_accs_{seed}.pkl"), "wb") as f:
        pickle.dump(q_acc, f)
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_q_cnts_{seed}.pkl"), "wb") as f:
        pickle.dump(q_cnt, f)

    # precisions, recalls, f1s
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_precisions_{seed}.pkl"), "wb") as f:
        pickle.dump(precision, f)
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_recalls_{seed}.pkl"), "wb") as f:
        pickle.dump(recall, f)
    with open(os.path.join(ckpt_path, f"{optimizer}_{seq_len}_f1s_{seed}.pkl"), "wb") as f:
        pickle.dump(f1, f)

# program main entry point
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--model_name",
        type=str,
        default="dkt",
        help="The name of the model to train. \
            The possible models are in [dkt]. \
            The default model is dkt."
    )
    parser.add_argument(
        '--dataset_name',
        type=str,
        default="ASSIST2009",
        help="The name of the dataset to use in training. \
            The possible datasets are in \
            [ASSIST2009]. \
            The default dataset is ASSIST2009."
    )

    # true_list 에 없으면 자동적으로 false가 됨.
    true_list = ['true', 'yes', '1', 't', 'y']

    parser.add_argument(
        '--use_wandb',
        type= lambda s: s.lower() in true_list,
        default=False,
        help="This option value is using wandb"
    )

    args = parser.parse_args()

    main(args.model_name, args.dataset_name, args.use_wandb)


import datetime
import json
import pymongo
import requests_oauthlib
import tqdm
import os

# API key
consumer_key = os.environ['twitter_consumer_key']
consumer_secret = os.environ['twitter_consumer_secret']
access_token_key = os.environ['twitter_access_token_key']
access_token_secret = os.environ['twitter_access_token_secret']
print("consumer_key",consumer_key,"consumer_secret",consumer_secret)
print("access_token_key",access_token_key,"access_token_secret",access_token_secret)

# Twitter Streaming API
twitter = requests_oauthlib.OAuth1Session(
	consumer_key, consumer_secret, access_token_key, access_token_secret)
uri = 'http://stream.twitter.com/1.1/statuses/sample.json'
r = twitter.get(uri, stream=True)
r.raise_for_status()

# Stored in mongoDB
mongo = pymongo.MongoClient()
for line in tqdm.tqdm(r.iter_lines(), unit='tweets', mininterval=1):
	if line:
		tweet = json.loads(line)
		tweet['_timestamp'] = datetime.datetime.utcnow().isoformat()
		mongo.twitter.sample.insert_one(tweet)


# Date: April 24th, 2018
# Author: Hasana Chaudry
# Class: Senior Colloquium
# Topic: Page Ranking
# Advisor: Kenneth Brakke
# Filename: pageRank.py

import numpy as np
import scipy as sc
#import pandas as pd
from fractions import Fraction

def float_format(vector, decimal):
    return np.round((vector).astype(np.float), decimals = decimal)

# Initializing three webpages. Each web page is assigned a probability of 1/3
n = Fraction(1, 3)

# Creates a 3x3 matrix that represents the transpose of an adjacency matrix
# Completely dense, rank-one teleportation matrix
E = np.matrix([[0, 0, 1], [Fraction(1,2), 0, 0], [Fraction(1,2), 1, 0]])

# Creates a 3x3 sparse matrix
# Sparse, stochastic matrix
S = np.zeros((3, 3))
S[:] = n

# Assigning the damping parameter (always between 0 and 1)
# The probability that when a user clicks on a link, they will continue browsing
a = 0.85

# The equation that gives the page rank values of links in the form of a matrix
# also called the Google Matrix
G = a * S + ((1 - a) * E)

# Creating a matrix, r, that holds the current PageRank values of the three pages
r = np.matrix([n, n, n])
r = np.transpose(r)

# Saving the initial r value
old_r = r

# Setting up a for loop that will go through a hundred iterations
for k in range(1,100):
    # Calculating the page rank value through each iteration
    r = G * r
    print(r)
    print("\n")

    # An if statement that breaks the loop when an iteration returns
    # the same page rank values as the previous iteration
    if(old_r == r).all():
        break
    old_r = r

# Outputting the results
print("Final Ranks: \n ")
print("Node A's rank: ", float_format(r, 6)[0])
print("Node B's rank: ", float_format(r, 6)[1])
print("Node C's rank: ", float_format(r, 6)[2])
print("\n")
print("Sum:", np.sum(r))


import pandas as pd

def day_1a():
    input = pd.read_csv('input.txt', header=None)
    sum = 0
    for index,row in input.iterrows():
        value = int (row[0] / 3) - 2
        sum += value
    print(sum)

day_1a()


some_list = ["a","b","c","b","d","m","n","n"]

duplicates = []

for char in some_list:
    if some_list.count(char) > 1:
        if char not in duplicates:
            duplicates.append(char)

print(duplicates) # ['b', 'n']

# Same solution using comprehension...

duplicates_1 = list(set([x for x in some_list if some_list.count(x) > 1]))
print(duplicates_1) # ['n', 'b']

Python/004 Functional Programming/009 Exercise Comprehension.py


from django import forms
from .models import Review

class ReviewForm(forms.ModelForm):

    class Meta:
        model = Review
        exclude = ('user','name','event',)

        widgets = {
            'review' : forms.Textarea(attrs={
                'class': 'form-control',
                'placeholder': 'Review'
            }),

        }


from __future__ import annotations
from copy import deepcopy
from exceptions import ConstraintViolationError
from typing import List

class SolverState(object):
    """
    This class resembles the scratch pad that a human would use when solving Sudoku. It tracks what is assigned in
    every cell, what is still possible for each cell, and what is still possible in each row and column. Most of the
    methods in here are related to manipulating that information and accessing it in different ways.

    This allows the algorithm to be separate from the data.
    """
    def __init__(self, board):
        self.board = board

        # This gives the remaining choices for cells in a row. When this is empty the row is solved.
        self.row_remaining = [[i for i in range(1, 10)] for _ in range(1, 10)]

        # This gives the remaining choices for cells in a column. When this is empty the column is solved.
        self.col_remaining = [[i for i in range(1, 10)] for _ in range(1, 10)]

        # cell_possibles[row][col] gives the possible values for each cell
        self.cell_possible = [[[i for i in range(1, 10)] for _ in range(1, 10)] for _ in range(1, 10)]

    def copy(self) -> SolverState:
        """ Returns a deep copy of this SolverState. Useful for undoing changes. """
        new_state = SolverState(deepcopy(self.board))
        new_state.cell_possible = deepcopy(self.cell_possible)
        new_state.row_remaining = deepcopy(self.row_remaining)
        new_state.col_remaining = deepcopy(self.col_remaining)
        return new_state

    def get_choices_for_cell(self, row: int, column: int) -> List[int]:
        """ Returns the list of remaining choices possible for the given cell """
        return self.cell_possible[row][column]

    def get_choices_for_cells_in_row(self, row) -> set[int]:
        """
        Returns the union of remaining possible choices for all the cells in the given row. This only includes
        unsolved cells because solved ones are no longer possible to assign.
        """
        choices = set()
        for col in range(9):
            # cells with one possibility are known
            if len(self.cell_possible[row][col]) != 1:
                choices.update(self.cell_possible[row][col])
        return choices

    def get_choices_for_cells_in_col(self, col: int) -> set[int]:
        """
        Returns the union of remaining possible choices for all the cells in the given column. This only includes
        unsolved cells because solved ones are no longer possible to assign.
        """
        # building a set explicitly is much faster than using itertools.chain(filter()))
        choices = set()
        for row in range(9):
            if len(self.cell_possible[row][col]) != 1:
                choices.update(self.cell_possible[row][col])
        return choices

    def get_unique_values_in_section(self, start_cell: (int, int), end_cell: (int, int)) -> list[int]:
        """
        Returns the unique values that are known within a given section, bounded by start_cell and end_cell.
        :param (int, int) start_cell: The upper left corner of the range (inclusive)
        :param (int, int) end_cell: The lower right corner of the range (exclusive)
        """
        # building a set explicitly is much faster than using itertools.chain(filter()))
        values_in_section = []
        for r in range(start_cell[0], end_cell[0]):
            for c in range(start_cell[1], end_cell[1]):
                if self.board[r][c] is not None:
                    values_in_section.append(self.board[r][c])
        return values_in_section

    def get_choices_for_row(self, row: int) -> list[int]:
        """ Returns the remaining possible choices for unsolved cells in the given row """
        return self.row_remaining[row]

    def get_choices_for_col(self, col: int) -> list[int]:
        """ Returns the remaining possible choices for unsolved cells in the given row """
        return self.col_remaining[col]

    def mark_impossible_in_cell(self, row, column, to_remove) -> bool:
        """
        Remove the given value from the list of remaining possibilities for the given cell
        :return bool True if anything was changed, False if the value was already impossible
        """
        if to_remove in self.cell_possible[row][column]:
            self.cell_possible[row][column].remove(to_remove)
            return True
        else:
            return False

    def mark_impossible_in_row(self, row: int, value: int):
        """ Remove the given value from the list of remaining possibilities for a given row """
        if value in self.row_remaining[row]:
            self.row_remaining[row].remove(value)

    def mark_impossible_in_col(self, col: int, value: int):
        """ Remove the given value from the list of remaining possibilities for a given row """
        if value in self.col_remaining[col]:
            self.col_remaining[col].remove(value)

    def set_choices_for_cell(self, row: int, column: int, value: list[int]):
        """ Sets the list of remaining possibilities for a given cell """
        self.cell_possible[row][column] = value

    def set_choices_for_row(self, row, new_choices: List[int]):
        """ Sets the list of remaining possibilities for a given row """
        self.row_remaining[row] = new_choices

    def set_choices_for_col(self, col, new_choices: List[int]):
        """ Sets the list of remaining possibilities for a given column """
        self.col_remaining[col] = new_choices

    def board_at(self, row: int, column: int) -> int:
        """ Returns the value of the given cell. Returns None if it does not have a known value. """
        return self.board[row][column]

    def is_cell_solved(self, row: int, column: int) -> bool:
        """ Returns whether the given cell has a known value """
        return self.board[row][column] is not None

    def get_row(self, row: int):
        """ Returns the given row of the board, including both solved and unsovled cells """
        return self.board[row]

    def get_column(self, col: int):
        """ Returns the given column of the board, including both solved and unsovled cells """
        return [v[col] for v in self.board]

    def update_board(self, row: int, column: int, value: int):
        """ Sets a value for the given cell in the board and updates the other possibility lists to match """
        self.board[row][column] = value

        # update all derived information
        self.set_choices_for_cell(row, column, [value])
        if value in self.row_remaining:
            self.row_remaining[row].remove(value)
        if value in self.col_remaining:
            self.col_remaining[column].remove(value)

    def is_solved(self) -> bool:
        """ Returns True if every cell in the board has a known value """
        for row in self.board:
            for cell in row:
                if not cell:
                    return False
        try:
            self.assert_still_valid()
        except ConstraintViolationError:
            return False

        return True

    def matches_expected(self, expected_solution) -> bool:
        """ Returns true if the current board matches the given expectation """
        matched = True
        for r in range(9):
            for c in range(9):
                if self.board[r][c] != expected_solution[r][c]:
                    return False
        return matched

    def assert_still_valid(self):
        """
        Ensures that all of the possiblity lists are consistent with each other. If they are not, it either
        indicates the solver has guessed an incorrect value (raises ConstraintViolationError) or there is a bug in the
        code (assertion failure)
        """
        # no two values in the same column:
        self._check_rows()

        # no two values in the same row:
        self._check_columns()

        # no two values in the same section
        for start_row in range(0, 7, 3):
            for start_col in range(0, 7, 3):
                self._check_section(start_row, start_row + 3, start_col, start_col + 3)

        self._assert_internal_consistency()

    def _check_rows(self):
        for r in range(9):
            row_values = set()
            for c in range(9):
                value = self.board[r][c]
                if value:
                    if value in row_values:
                        raise ConstraintViolationError(f"Cell {r, c} value {value} is duplicatedd in row")
                    row_values.add(value)

    def _check_columns(self):
        for c in range(9):
            col_values = set()
            for r in range(9):
                value = self.board[r][c]
                if value:
                    if self.board[r][c] in col_values:
                        raise ConstraintViolationError(f"Cell {r, c} is duplicated in column")
                    col_values.add(value)

    def _check_section(self, start_row, end_row, start_col, end_col):
        nums_in_section = set()
        for r in range(start_row, end_row):
            for c in range(start_col, end_col):
                if self.board[r][c] in nums_in_section:
                    raise ConstraintViolationError(
                        f"Duplicate value {self.board[r][c]} in section {(start_row, end_row), (start_col, end_col)}")
                if self.board[r][c] is not None:
                    nums_in_section.add(self.board[r][c])

    def _assert_internal_consistency(self):
        # any of these assertions that fail indicate a bug in the code
        for r in range(9):
            for c in range(9):
                assert(self.get_choices_for_cell(r, c) != 0)

                # if there are no more possibiliites, yet this cell has not been solved, there is a bug
                if len(self.get_choices_for_cell(r, c)) == 1:
                    assert(self.board[r][c] is not None)

                if self.board[r][c] is not None:
                    assert(self.board[r][c] not in self.row_remaining)
                    assert(self.board[r][c] not in self.col_remaining)
                    assert(self.board[r][c] == self.get_choices_for_cell(r, c)[0])
                    assert(len(self.get_choices_for_cell(r, c)) == 1)


from __future__ import print_function
import os
import math
import numpy as np
import cntk as C
import _cntk_py
import cntk.io.transforms as xforms

# Paths relative to current python file.
abs_path   = os.path.dirname(os.path.abspath(__file__))
data_path  = os.path.join(abs_path, "..", "..", "..", "DataSets", "CIFAR-10")
model_path = os.path.join(abs_path, "Models")

# model dimensions
image_height = 32
image_width  = 32
num_channels = 3  # RGB
num_classes  = 10

# Define the reader for both training and evaluation action.
def create_reader(map_file, mean_file, is_training):
    if not os.path.exists(map_file) or not os.path.exists(mean_file):
        raise RuntimeError("File '%s' or '%s' does not exist. Please run install_cifar10.py from DataSets/CIFAR-10 to fetch them" %
                           (map_file, mean_file))

    # transformation pipeline for the features has jitter/crop only when training
    transforms = []
    if is_training:
        transforms += [
            xforms.crop(crop_type='RandomSide', side_ratio=0.8, jitter_type='uniRatio') # train uses jitter
        ]
    transforms += [
        xforms.scale(width=image_width, height=image_height, channels=num_channels, interpolations='linear'),
        xforms.mean(mean_file)
    ]
    # deserializer
    return C.io.MinibatchSource(C.io.ImageDeserializer(map_file, C.io.StreamDefs(
        features=C.io.StreamDef(field='image', transforms=transforms), # first column in map file is referred to as 'image'
        labels=C.io.StreamDef(field='label', shape=num_classes))),   # and second as 'label'
        randomize=is_training)

# Local Response Normalization layer. See Section 3.3 of the paper:
# https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf
# The mathematical equation is:
#   b_{x,y}^i=a_{x,y}^i/(k+\alpha\sum_{j=max(0,i-n)}^{min(N-1, i+n)}(a_{x,y}^j)^2)^\beta
# where a_{x,y}^i is the activity of a neuron comoputed by applying kernel i at position (x,y)
# N is the total number of kernals, n is half normalization width.
def LocalResponseNormalization(k, n, alpha, beta, name=''):
    x = C.placeholder(name='lrn_arg')
    x2 = C.square(x)
    # reshape to insert a fake singleton reduction dimension after the 3th axis (channel axis). Note Python axis order and BrainScript are reversed.
    x2s = C.reshape(x2, (1, C.InferredDimension), 0, 1)
    W = C.constant(alpha/(2*n+1), (1,2*n+1,1,1), name='W')
    # 3D convolution with a filter that has a non 1-size only in the 3rd axis, and does not reduce since the reduction dimension is fake and 1
    y = C.convolution (W, x2s)
    # reshape back to remove the fake singleton reduction dimension
    b = C.reshape(y, C.InferredDimension, 0, 2)
    den = C.exp(beta * C.log(k + b))
    apply_x = C.element_divide(x, den)
    return apply_x

# Train and evaluate the network.
def convnetlrn_cifar10_dataaug(reader_train, reader_test, epoch_size=50000, max_epochs = 80):
    _cntk_py.set_computation_network_trace_level(0)

    # Input variables denoting the features and label data
    input_var = C.input_variable((num_channels, image_height, image_width))
    label_var = C.input_variable((num_classes))

    # apply model to input
    scaled_input = C.element_times(C.constant(0.00390625), input_var)

    with C.layers.default_options (activation=C.relu, pad=True):
        z = C.layers.Sequential([
            C.layers.For(range(2), lambda : [
                C.layers.Convolution2D((3,3), 64),
                C.layers.Convolution2D((3,3), 64),
                LocalResponseNormalization (1.0, 4, 0.001, 0.75),
                C.layers.MaxPooling((3,3), (2,2))
            ]),
            C.layers.For(range(2), lambda i: [
                C.layers.Dense([256,128][i]),
                C.layers.Dropout(0.5)
            ]),
            C.layers.Dense(num_classes, activation=None)
        ])(scaled_input)

    # loss and metric
    ce = C.cross_entropy_with_softmax(z, label_var)
    pe = C.classification_error(z, label_var)

    # training config
    minibatch_size = 64

    # Set learning parameters
    lr_per_sample          = [0.0015625]*20 + [0.00046875]*20 + [0.00015625]*20 + [0.000046875]*10 + [0.000015625]
    lr_schedule            = C.learning_parameter_schedule_per_sample(lr_per_sample, epoch_size=epoch_size)
    mms                    = [0]*20 + [0.9983347214509387]*20 + [0.9991670137924583]
    mm_schedule            = C.learners.momentum_schedule_per_sample(mms, epoch_size=epoch_size)
    l2_reg_weight          = 0.002

    # trainer object
    learner = C.learners.momentum_sgd(z.parameters, lr_schedule, mm_schedule,
                                        unit_gain = True,
                                        l2_regularization_weight = l2_reg_weight)
    progress_printer = C.logging.ProgressPrinter(tag='Training', num_epochs=max_epochs)
    trainer = C.Trainer(z, (ce, pe), learner, progress_printer)

    # define mapping from reader streams to network inputs
    input_map = {
        input_var: reader_train.streams.features,
        label_var: reader_train.streams.labels
    }

    C.logging.log_number_of_parameters(z) ; print()

    # perform model training
    for epoch in range(max_epochs):       # loop over epochs
        sample_count = 0
        while sample_count < epoch_size:  # loop over minibatches in the epoch
            data = reader_train.next_minibatch(min(minibatch_size, epoch_size-sample_count), input_map=input_map) # fetch minibatch.
            trainer.train_minibatch(data)                                   # update model with it
            sample_count += trainer.previous_minibatch_sample_count         # count samples processed so far

        trainer.summarize_training_progress()
        z.save(os.path.join(model_path, "ConvNet_CIFAR10_DataAug_{}.dnn".format(epoch)))

    ### Evaluation action
    epoch_size     = 10000
    minibatch_size = 16

    # process minibatches and evaluate the model
    metric_numer    = 0
    metric_denom    = 0
    sample_count    = 0
    minibatch_index = 0

    while sample_count < epoch_size:
        current_minibatch = min(minibatch_size, epoch_size - sample_count)
        # Fetch next test min batch.
        data = reader_test.next_minibatch(current_minibatch, input_map=input_map)
        # minibatch data to be trained with
        metric_numer += trainer.test_minibatch(data) * current_minibatch
        metric_denom += current_minibatch
        # Keep track of the number of samples processed so far.
        sample_count += data[label_var].num_samples
        minibatch_index += 1

    print("")
    print("Final Results: Minibatch[1-{}]: errs = {:0.2f}% * {}".format(minibatch_index+1, (metric_numer*100.0)/metric_denom, metric_denom))
    print("")

    return metric_numer/metric_denom

if __name__=='__main__':
    reader_train = create_reader(os.path.join(data_path, 'train_map.txt'), os.path.join(data_path, 'CIFAR-10_mean.xml'), True)
    reader_test  = create_reader(os.path.join(data_path, 'test_map.txt'), os.path.join(data_path, 'CIFAR-10_mean.xml'), False)

    convnetlrn_cifar10_dataaug(reader_train, reader_test)


# -*- encoding: utf-8 -*-

# example: python stations.py stations.csv portals.csv

import os
import sys
import math
import pandas as pd
import numpy as np

vocabPath = sys.argv[1]
filePath = sys.argv[2]

vocabDf = pd.read_csv(vocabPath, sep=',', header=0, encoding='utf-8', index_col=0, names=['stationId', 'lineId', 'nodeId', 'id_osm', 'stationName', 'stationName_en', 'lon', 'lat', 'lineName'])
#['stationName', 'stationName_en', 'lineName', 'stationId', 'lineId', 'nodeId', 'lat', 'lon']
del vocabDf['id_osm']
del vocabDf['lat']
del vocabDf['lon']
sourceDf = pd.read_csv(filePath, sep=',', header=0, encoding='utf-8', names=['id', 'id2', 'meetcode', 'station', 'line', 'portalName_ru', 'portalName_en','station_id', 'line_id', '0_x', '0_y', 'direction', 'min_width', 'min_steps', 'min_rail_steps', 'lift', 'lift_minus_steps', 'min_lift_steps', 'min_rail_width', 'max_rail_width', 'max_angle', 'max_slope', 'stairways', 'pandusUnavailable', 'wheelchairFriendlyRoutes', 'handicappedFriendlyRoutes', 'luggageFriendlyRoutes', 'Creator', 'Closed', 'Comment'])

''' Calculated columns
sourceDf['max_slope'] = np.tan(np.radians(sourceDf['max_angle'])) * 100
sourceDf['wheelchairFriendlyRoutes'] = ((sourceDf['min_lift_steps'] == 0 ) | (sourceDf['min_rail_steps'] == 0) | (sourceDf['min_rail_steps'] - sourceDf['lift_minus_steps'] <= 0) & (sourceDf['stairways'] == 0) & (sourceDf['min_width'] >= 740) & (sourceDf['max_slope'] <= 15) & (sourceDf['pandusUnavailable'] == 0)) * 1
sourceDf['handicappedFriendlyRoutes'] = ((sourceDf['min_lift_steps'] < 3) | (sourceDf['min_rail_steps'] < 3) | (sourceDf['min_rail_steps'] - sourceDf['lift_minus_steps'] <= 3) & (sourceDf['max_slope'] <= 15)) * 1
sourceDf['luggageFriendlyRoutes'] = ((sourceDf['min_lift_steps'] < 3) | (sourceDf['min_rail_steps'] < 3) | (sourceDf['min_rail_steps'] - sourceDf['lift_minus_steps'] <= 3) & (sourceDf['min_width'] >= 700)) * 1
'''
sourceDf['stairwayAvailableRoutes'] =  (sourceDf['stairways'] > 0) * 1
sourceDf['liftAvailableRoutes'] =  (sourceDf['lift'] > 0) * 1
# stations
# ['id', 'id2', 'station', 'line', 'entrance_name', 'station_id', 'line_id', '0_x', '0_y', 'direction', 'min_width', 'min_steps', 'min_rail_steps', 'lift', 'lift_minus_steps', 'min_lift_steps', 'min_rail_width', 'max_rail_width', 'max_angle', 'max_slope', 'stairways', 'wheelchairFriendlyRoutes', 'handicappedFriendlyRoutes', 'luggageFriendlyRoutes', 'Creator', 'Closed', 'Comment']
# ['stationName', 'stationName_en', 'lineName', 'stationId', 'lineId', 'nodeId', 'lat', 'lon']
# Calculating all stuff

#stationId
#stationName
#lineName
#lineId

routes = pd.pivot_table(sourceDf, values='station', rows='station_id', cols='direction', fill_value=0, aggfunc = 'count')
routesIn = pd.DataFrame({'routesIn' : routes['in'] + routes['both']})
routesOut = pd.DataFrame({'routesOut' : routes['out'] + routes['both']})

minTaper = pd.DataFrame({'minTaper' : sourceDf.groupby(by='station_id')['min_width'].min()})
maxTaper = pd.DataFrame({'maxTaper' : sourceDf.groupby(by='station_id').max()['min_width']})
minStairs = pd.DataFrame({'minStairs' : sourceDf.groupby(by='station_id').min()['min_steps']})
avStairs = pd.DataFrame({'avStairs' : sourceDf.groupby(by='station_id').mean()['min_steps']})
maxStairs = pd.DataFrame({'maxStairs' : sourceDf.groupby(by='station_id').max()['min_steps']})
minRailsStairs = pd.DataFrame({'minRailsStairs' : sourceDf.groupby(by='station_id').min()['min_rail_steps']})
avRailsStairs = pd.DataFrame({'avRailsStairs' : sourceDf.groupby(by='station_id').mean()['min_rail_steps']})
maxRailsStairs = pd.DataFrame({'maxRailsStairs' : sourceDf.groupby(by='station_id').max()['min_rail_steps']})
lift = pd.DataFrame({'lift' : sourceDf.groupby(by='station_id').sum()['lift']})
minLiftAmount = pd.DataFrame({'minLiftAmount' : sourceDf.groupby(by='station_id').min()['lift']})
maxLiftAmount = pd.DataFrame({'maxLiftAmount' : sourceDf.groupby(by='station_id').max()['lift']})
minLiftStairs = pd.DataFrame({'minLiftStairs' : sourceDf.groupby(by='station_id')['min_lift_steps'].min()})
avLiftStairs = pd.DataFrame({'avLiftStairs' : sourceDf.groupby(by='station_id')['min_lift_steps'].mean()})
maxLiftStairs = pd.DataFrame({'maxLiftStairs' : sourceDf.groupby(by='station_id')['min_lift_steps'].max()})
minStairways = pd.DataFrame({'minStairways' : sourceDf.groupby(by='station_id')['stairways'].min()})
maxStairways = pd.DataFrame({'maxStairways' : sourceDf.groupby(by='station_id').max()['stairways']})

stairwayAvailableRoutesAll = pd.pivot_table(sourceDf, values='stairwayAvailableRoutes', rows='station_id', cols='direction', fill_value=0, aggfunc = 'sum')
stairwayAvailableRoutesIn = pd.DataFrame({'stairwayAvailableRoutesIn' : stairwayAvailableRoutesAll['in'] + stairwayAvailableRoutesAll['both']})
stairwayAvailableRoutesOut = pd.DataFrame({'stairwayAvailableRoutesOut' : stairwayAvailableRoutesAll['out'] + stairwayAvailableRoutesAll['both']})

liftAvailableRoutesAll = pd.pivot_table(sourceDf, values='liftAvailableRoutes', rows='station_id', cols='direction', fill_value=0, aggfunc = 'sum')
liftAvailableRoutesIn = pd.DataFrame({'liftAvailableRoutesIn' : liftAvailableRoutesAll['in'] + liftAvailableRoutesAll['both']})
liftAvailableRoutesOut = pd.DataFrame({'liftAvailableRoutesOut' : liftAvailableRoutesAll['out'] + liftAvailableRoutesAll['both']})

wheelchairFriendlyRoutesAmount = pd.DataFrame({'wheelchairFriendlyRoutesAmount' : sourceDf.groupby(by='station_id')['wheelchairFriendlyRoutes'].sum()})
wheelchairFriendlyRoutesAll = pd.pivot_table(sourceDf, values='wheelchairFriendlyRoutes', rows='station_id', cols='direction', fill_value=0, aggfunc = 'sum')
wheelchairFriendlyRoutesIn = pd.DataFrame({'wheelchairFriendlyRoutesIn' : wheelchairFriendlyRoutesAll['in'] + wheelchairFriendlyRoutesAll['both']})
wheelchairFriendlyRoutesOut = pd.DataFrame({'wheelchairFriendlyRoutesOut' : wheelchairFriendlyRoutesAll['out'] + wheelchairFriendlyRoutesAll['both']})

handicappedFriendlyRoutesAmount = pd.DataFrame({'handicappedFriendlyRoutesAmount' : sourceDf.groupby(by='station_id')['handicappedFriendlyRoutes'].sum()})
handicappedFriendlyRoutesAll = pd.pivot_table(sourceDf, values='handicappedFriendlyRoutes', rows='station_id', cols='direction', fill_value=0, aggfunc = 'sum')
handicappedFriendlyRoutesIn = pd.DataFrame({'handicappedFriendlyRoutesIn' : handicappedFriendlyRoutesAll['in'] + handicappedFriendlyRoutesAll['both']})
handicappedFriendlyRoutesOut = pd.DataFrame({'handicappedFriendlyRoutesOut' : handicappedFriendlyRoutesAll['out'] + handicappedFriendlyRoutesAll['both']})

luggageFriendlyRoutesAmount = pd.DataFrame({'luggageFriendlyRoutesAmount' : sourceDf.groupby(by='station_id')['luggageFriendlyRoutes'].sum()})
luggageFriendlyRoutesAll = pd.pivot_table(sourceDf, values='luggageFriendlyRoutes', rows='station_id', cols='direction', fill_value=0, aggfunc = 'sum')
luggageFriendlyRoutesIn = pd.DataFrame({'luggageFriendlyRoutesIn' : luggageFriendlyRoutesAll['in'] + luggageFriendlyRoutesAll['both']})
luggageFriendlyRoutesOut = pd.DataFrame({'luggageFriendlyRoutesOut' : luggageFriendlyRoutesAll['out'] + luggageFriendlyRoutesAll['both']})

# Merging all the results
#DataFrame.merge(right, how='inner', on=None, left_on=None, right_on=None, left_index=False, right_index=False, sort=False, suffixes=('_x', '_y'), copy=True)

result = vocabDf.join(routesIn, how='inner', sort=False)
result = result.join(routesOut, how='inner', sort=False)

result = result.join(minTaper, how='inner', sort=False)
result = result.join(maxTaper, how='inner', sort=False)
result = result.join(minStairs, how='inner', sort=False)
result = result.join(np.round(avStairs, decimals=0).astype(int), how='inner', sort=False)
result = result.join(maxStairs, how='inner', sort=False)
result = result.join(minRailsStairs, how='inner', sort=False)
result = result.join(np.round(avRailsStairs, decimals=0).astype(int), how='inner', sort=False)
result = result.join(maxRailsStairs, how='inner', sort=False)
result = result.join(lift, how='inner', sort=False)
result = result.join(minLiftAmount, how='inner', sort=False)
result = result.join(maxLiftAmount, how='inner', sort=False)
result = result.join(minLiftStairs, how='inner', sort=False)
result = result.join(np.round(avLiftStairs, decimals=0).astype(int), how='inner', sort=False)
result = result.join(maxLiftStairs, how='inner', sort=False)
result = result.join(minStairways, how='inner', sort=False)
result = result.join(maxStairways, how='inner', sort=False)

result = result.join(stairwayAvailableRoutesIn, how='inner', sort=False)
result = result.join(stairwayAvailableRoutesOut, how='inner', sort=False)
result['stairwayAvailableRoutesAmount'] = result['stairwayAvailableRoutesIn'] + result['stairwayAvailableRoutesOut']

result = result.join(liftAvailableRoutesIn, how='inner', sort=False)
result = result.join(liftAvailableRoutesOut, how='inner', sort=False)
result['liftAvailableRoutesAmount'] = result['liftAvailableRoutesIn'] + result['liftAvailableRoutesOut']

result['wheelchairFriendlyRoutes'] = (wheelchairFriendlyRoutesAmount > 0) * 1
#result = result.join(wheelchairFriendlyRoutesAmount, how='inner', sort=False)
result = result.join(wheelchairFriendlyRoutesIn, how='inner', sort=False)
result = result.join(wheelchairFriendlyRoutesOut, how='inner', sort=False)
result['wheelchairFriendlyRoutesAmount'] = result['wheelchairFriendlyRoutesIn'] + result['wheelchairFriendlyRoutesOut']
result['handicappedFriendlyRoutes'] = (handicappedFriendlyRoutesAmount > 0) * 1
#result = result.join(handicappedFriendlyRoutesAmount, how='inner', sort=False)
result = result.join(handicappedFriendlyRoutesIn, how='inner', sort=False)
result = result.join(handicappedFriendlyRoutesOut, how='inner', sort=False)
result['handicappedFriendlyRoutesAmount'] = result['handicappedFriendlyRoutesIn'] + result['handicappedFriendlyRoutesOut']
result['luggageFriendlyRoutes'] = (luggageFriendlyRoutesAmount > 0) * 1
#result = result.join(luggageFriendlyRoutesAmount, how='inner', sort=False)
result = result.join(luggageFriendlyRoutesIn, how='inner', sort=False)
result = result.join(luggageFriendlyRoutesOut, how='inner', sort=False)
result['luggageFriendlyRoutesAmount'] = result['luggageFriendlyRoutesIn'] + result['luggageFriendlyRoutesOut']

resultPath = os.path.join(os.path.dirname(filePath), 'stationsReport.csv')
result.to_csv(resultPath, encoding='utf-8', index_label='stationId')


import sys
input=sys.stdin.readline

n=int(input())
xy=[]

for i in range(n):
    x,y=map(int,input().split())
    xy.append((x,y))

resultX=0
resultY=0

for i in range(n):
    if i!=n-1:
        resultX+=xy[i][0]*xy[i+1][1]
        resultY+=xy[i+1][0]*xy[i][1]
    else:
        resultX+=xy[i][0]*xy[0][1]
        resultY+=xy[0][0]*xy[i][1]

area=abs(resultX-resultY)/2

print(round(area*10)/10)


def find(num,binas,s,ss,M,K,check):
    if len(s)==M:
        ss.append(s)
        return
    a1=(2**K-1)&(num<<1)
    a2=a1+1
    if a1 in binas:
        binas.remove(a1)
        check.append(a1)
        s+="0"
        if len(s)==M:
            binas.append(a1)
            check.remove(a1)
            s = s[:-1]
        else:
            find(a1,binas,s,ss,M,K,check)
            binas.append(a1)
            check.remove(a1)
            s=s[:-1]
    if a2 in binas:
        binas.remove(a2)
        s+="1"
        check.append(a2)
        find(a2,binas,s,ss,M,K,check)
        binas.append(a2)
        check.remove(a2)
        s=s[:-1]
    return

K=int(input())
M=2**K
binas=[]
for i in range(M):
    binas.append(i)
res=binas[0]
binas.remove(0)
ss=[]
s=""
for i in range(K):s+="0"
find(0,binas,s,ss,M,K,[])
ss.sort()
print(M,ss[0])


#!/usr/bin/python3
import json

from flask import Flask

app = Flask(__name__)

@app.route('/')
def task1():
    with open('task1-data.json', 'r') as f:
        return json.loads(f.read())

if __name__ == '__main__':
    app.run(debug=True)


# encoding=GBK
"""Conv2D

    - 和骨干网络的第0层的启动结构类似
        - 变化的只有不固定的卷积核与通道数
        - 用来适应3种情况下输出的内容

    - 封装步骤：
        1. conv
        2. batch_norm
        3. LeaKyRelU
"""
import torch.nn as nn
from collections import OrderedDict

class Conv2D:
    @staticmethod
    def conv2d(filter_in, filter_out, kernel_size):
        pad = (kernel_size - 1) // 2 if kernel_size else 0
        return nn.Sequential(OrderedDict([
            ("conv", nn.Conv2d(filter_in, filter_out, kernel_size=kernel_size, stride=1, padding=pad, bias=False)),
            ("bn", nn.BatchNorm2d(filter_out)),
            ("relu", nn.LeakyReLU(0.1)),
        ]))

if __name__ == '__main__':
    # img = torch.randn((1, 3, 200, 200))
    out = Conv2D.conv2d(3, 10, 3)
    print(out)


# -*- coding=utf-8
import sys
import logging
import json
import time
import os

def write_content_to_file(file_name, content):
    file_ob = open(file_name, 'w')
    file_ob.write(content)
    file_ob.close()

def read_file_content(file_name):
    file_ob = open(file_name, 'r')
    content = file_ob.read()
    file_ob.close()
    return content

def main():
    result = {"items": []}

    content = read_file_content('history.log')
    if len(content) == 0:
        result["items"].append({
            "title":'已上传 0 张图片',
            "subtitle": "移动到指定图片，按下 Cmd + Y 可查看图片",
            "arg": "noPic",
            "icon": "5E995555-07AF-4314-B882-C89ABAF2ED7A.png"})
        print(json.dumps(result))
        return -1
    answers = content.split("\n")

    if not answers:
        result["items"].append({
            "title":'已上传 0 张图片',
            "subtitle": "移动到指定图片，按下 Cmd + Y 可查看图片",
            "arg": "noPic",
            "icon": "5E995555-07AF-4314-B882-C89ABAF2ED7A.png"})
        print(json.dumps(result))
        return -1

    result["items"].append({
            "title":'已上传 ' + str(len(answers) / 2) + ' 张图片，移动后 Cmd + Y 可查看图片',
            "subtitle": "移动后 Enter 可复制对于图片链接",
            "arg": "noPic",
            "icon": "5E995555-07AF-4314-B882-C89ABAF2ED7A.png"})
    i = 0
    while(i < len(answers) - 1):
        result["items"].append({
            "title": answers[i],
            "subtitle": answers[i + 1],
            "arg": answers[i + 1],
            "autocomplete": answers[i],
            "icon": "5E995555-07AF-4314-B882-C89ABAF2ED7A.png"
        })
        i = i + 2
    print(json.dumps(result))

if __name__ == '__main__':
    main()


"""Advent of Code - 2021 Day 25"""

from aoc.geometry import Grid, Point

def move(grid):
    width = grid.width()
    height = grid.height()
    move_east = {}
    move_south = {}

    for pos, value in grid.items():
        if value == '>':
            next_pos = pos + Point(1, 0)
            next_pos.x %= width
            if grid[next_pos] == '.':
                move_east[pos] = next_pos

    for pos, next_pos in move_east.items():
        grid[pos] = '.'
        grid[next_pos] = '>'

    for pos, value in grid.items():
        if value == 'v':
            next_pos = pos + Point(0, 1)
            next_pos.y %= height
            if grid[next_pos] == '.':
                move_south[pos] = next_pos

    for pos, next_pos in move_south.items():
        grid[pos] = '.'
        grid[next_pos] = 'v'

    return bool(move_east) or bool(move_south)

def part1(input):
    grid = Grid.from_rows(input.lines())
    steps = 1
    while move(grid):
        steps += 1
    return steps

def part2(input):
    pass


import serial.tools.list_ports

def get_ports():
    ports = list(serial.tools.list_ports.comports())
    for port in ports:
        if port.manufacturer.startswith("STM"):
            port_number = port.device
    return port_number

def receive_data():
    try:
        value = iot_device.readline()
        print(value)
    except:
        print("Nothing to print")

def send_data(data):
    try:
        iot_device.write(data.encode())
    except:
        print("Nothing to send")

#iot_device = serial.Serial(port=get_ports(),baudrate=115200, bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,timeout=1)
#while True:
#   try:
#        value = iot_device.readline()
#        print(value)
#    except:
#        print("Nothing to print")

while True:
    receive_data()
    send_data('A45')


from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render, get_object_or_404
from .forms import PostForm, CommentForm
from .models import Post, Group, User, Follow
from django.views.decorators.cache import cache_page
from django.core.cache import cache
from django.conf import settings
from django.http import HttpResponseRedirect

@cache_page(20)
def index(request):
    posts = cache.get('index_page')
    if posts is None:
        posts = Post.objects.all()
        cache.set('index_page', posts, timeout=20)
    paginator = Paginator(posts, 10)
    page_number = request.GET.get('page')
    page = paginator.get_page(page_number)
    return render(request,
                  'posts/index.html',
                  {'page': page, 'post': posts})

def group_posts(request, slug):
    group = get_object_or_404(Group, slug=slug)
    post = group.posts.all()

    paginator = Paginator(post, 10)
    page_number = request.GET.get('page')
    page = paginator.get_page(page_number)
    return render(request,
                  'posts/group.html',
                  {'page': page, 'post': post, 'group': group})

def profile(request, username):
    author = get_object_or_404(User, username=username)
    posts = author.posts.all()

    paginator = Paginator(posts, 10)
    page_num = request.GET.get('page')
    page = paginator.get_page(page_num)

    following = False
    if (not request.user.is_anonymous
        and Follow.objects.filter(
            user=request.user, author=author).exists()):
        following = True

    return render(request,
                  'posts/profile.html', {
                      'author': author,
                      'page': page,
                      'following': following})

def post_view(request, username, post_id):
    author = get_object_or_404(User, username=username)
    post = author.posts.get(pk=post_id)
    form = CommentForm()
    following = False
    if (not
        request.user.is_anonymous and Follow.objects.filter(
            user=request.user, author=author).exists()):
        following = True

    return render(request,
                  'posts/post.html', {
                      'author': author,
                      'post': post,
                      'form': form,
                      'following': following})

@login_required
def new_post(request):
    form = PostForm(request.POST, files=request.FILES or None)
    if form.is_valid():
        post = form.save(commit=False)
        post.author = request.user
        post.save()
        return redirect('/')
    return render(request, 'posts/new_post.html', {'form': form})

@login_required
def post_edit(request, username, post_id):
    post = get_object_or_404(Post, author__username=username, pk=post_id)
    author = post.author
    if request.user != author:
        return redirect("post", username=username, post_id=post_id)
    form = PostForm(
        request.POST or None, files=request.FILES or None, instance=post)
    if form.is_valid():
        post = form.save(commit=False)
        post.save()
        return redirect("post", username=username, post_id=post_id)
    return render(request,
                  'posts/new_post.html',
                  {'form': form,
                   'post': post,
                   'is_edit': True})

def page_not_found(request, exception):
    return render(
        request,
        "misc/404.html",
        {"path": request.path},
        status=404
    )

def server_error(request):
    return render(request, "misc/500.html", status=500)

@login_required
def add_comment(request, username, post_id):
    post = get_object_or_404(Post, pk=post_id)
    form = CommentForm(request.POST or None)
    if form.is_valid():
        comment = form.save(commit=False)
        comment.post = post
        comment.author = request.user
        comment.save()
        return redirect("post", username=username, post_id=post_id)
    return render(
        request, 'includes/comments.html', {
            'form': form,
            'username': request.user,
            'post_id': post_id})

@login_required
def follow_index(request):
    posts = Post.objects.filter(author__following__user=request.user)

    paginator = Paginator(posts, 10)
    page_num = request.GET.get('page')
    page = paginator.get_page(page_num)

    return render(request, "posts/follow.html", {'page': page})

@login_required
def profile_follow(request, username):
    author = get_object_or_404(User, username=username)
    if request.user != author and (
        not Follow.objects.filter(
            user=request.user, author=author).exists()):
        Follow.objects.create(user=request.user, author=author)
    return redirect('profile', username)

@login_required
def profile_unfollow(request, username):
    author = get_object_or_404(User, username=username)
    post_delete = Follow.objects.get(user=request.user, author=author)
    post_delete.delete()
    return redirect('profile', username)

def set_language(request):
    lang = request.GET.get('l', 'en')
    request.session[settings.LANGUAGE_SESSION_KEY] = lang
    response = HttpResponseRedirect(request.META.get('HTTP_REFERER', '/'))
    response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang)
    return response


n = int(input())
if n > 5000:
    exit()
tree = [[] for _ in range(n)]
for _ in range(n - 1):
    a, b = map(int, input().split())
    tree[a - 1].append(b - 1)
    tree[b - 1].append(a - 1)

parent = [0] * n
order = []
stack = [0]
while stack:
    x = stack.pop()
    order.append(x)
    for y in tree[x]:
        if y == parent[x]:
            continue
        parent[y] = x
        stack.append(y)

for _ in range(int(input())):
    k, *v, = map(int, input().split())
    mark = [0] * n
    for x in v:
        mark[x - 1] = 1
    dp = [0] * n
    for x in order[::-1]:
        dp[x] = mark[x]
        for y in tree[x]:
            if y == parent[x]:
                continue
            dp[x] += dp[y]
    ans = 0
    for c in dp:
        if c == 0 or c == k:
            continue
        ans += 1
    print(ans)


"""to do: default value einfuegen"""
from xml.sax.handler import ContentHandler

class ProcessHandler(ContentHandler):
	def __init__(self):
		self.result_head = ""
		self.result_body = ""
		self.result_tail = ""
		self.result = ""
		self.activ = [] #contains open tags
		self.inputs={} #contains the inputs
		self.final_outputs=[]
		self.activ_process=""
		self.process_inputs=[]
		self.process_outputs=[]
		self.process_name=""
		self.wps_outputs=[]
		self.trye=False
		self.catch=False
		self.count_t=0 # count of additional tabstops
		self.synchron = True #execution modus, default is synchron
		self.sleepSecs= 1 # seconds to wait at asynchronus executions

	def startElement(self,name,attrs):
		if name == "workflow":
			self.process_name=attrs['identifier']
			self.result_head+="from owslib.wps import WebProcessingService \n"
			self.result_head+="from pywps.Process import WPSProcess \n"
			self.result_head+="from owslib.wps import monitorExecution\n"
			self.result_head+="import sys\n"
			self.result_head+="from pywps import config\n"
			self.result_head+="import time\n"
			self.result_head+="class Process(WPSProcess): \n"
			self.result_head+="\tdef __init__(self): \n "
			self.result_head+="\t\tWPSProcess.__init__(self, "
			self.result_head+="identifier = \'"+ attrs['identifier']+"\', "
			self.result_head+="title=\'Process Chain\', "
			self.result_head+="version = \'0.1\',"
			self.result_head+="storeSupported = \'true\', "
			self.result_head+="statusSupported = \'true\', "
			self.result_head+="abstract=\'resulting process chain\')\n"
		if name == "inputs":
			self.activ.append(name)

		if name == "input" and self.activ[-1] == 'inputs':

			if attrs['type']=="literal":
				self.inputs[attrs['localIdentifier']]=attrs['defaultValue']

				self.result_head+="\t\tself."+attrs['localIdentifier']+" = self.addLiteralInput(identifier= \'" + attrs['localIdentifier'] + "\' , title= \'" + attrs['title']+"\'"

				if "defaultValue" in attrs:
					self.result_head+=" ,default=\'"+ attrs['defaultValue']+"\'"
				self.result_head+=") \n"
			if attrs['type'] == "complex":
				self.inputs[attrs['localIdentifier']]=attrs['defaultValue']

				self.result_head+="\t\tself."+attrs['localIdentifier']+" = self.addComplexInput(identifier= \'" + attrs['localIdentifier'] + "\' , title= \'" + attrs['title']+"\',formats=[{\'mimeType\':\'"+attrs['mimeType']+"\'}])\n"

		if name == "try":
			self.trye = True

		if name == "catch":
			self.catch = True
			self.trye = False

		if name == "startProcess":
			self.activ.append(name)
			self.activ_process=attrs['processID']

			if self.trye == True:
				self.result_body+="\t\ttry:\n"
				self.count_t=1

			if self.catch == True:
				self.result_body+="\t\texcept:\n"
				self.count_t=1

			elif self.catch and self.trye == False:
				self.count_t=0

			self.result_body+=self.count_t*"\t"+"\t\twps = WebProcessingService(\'"+ attrs['service'] + "\', verbose=True, skip_caps=True)\n"
			self.result_body+=self.count_t*"\t"+"\t\tidentifier = \'" + attrs['identifier'] + "\' \n"

			#Get the outputs in order to build request
			self.result_body+=self.count_t*"\t"+"\t\tdescription = wps.describeprocess(identifier)\n"
			self.result_body+=self.count_t*"\t"+"\t\twps_outputs=[]\n"
			self.result_body+=self.count_t*"\t"+"\t\tfor item in description.processOutputs:\n"
			self.result_body+=self.count_t*"\t"+"\t\t\tif item.dataType == \'ComplexOutput\':\n"
			self.result_body+=self.count_t*"\t"+"\t\t\t\twps_outputs.append((item.identifier, True))\n"
			self.result_body+=self.count_t*"\t"+"\t\t\telse: wps_outputs.append((item.identifier, False))\n"

			#synchron/asynchron process execution
			if 'synchron' in attrs:
				if attrs['synchron'] == 'True':
					self.synchron = True
					#if 'sleepSecs' in attrs:
					self.sleepSecs=30 #attrs['sleepSecs']

				elif attrs['synchron'] == 'False':
					self.synchron = False

		if name == "input" and self.activ[-1] == "startProcess":

			if 'sourceIdentifier' in attrs:
				self.process_inputs.append(("\'"+attrs['identifier']+"\'","str(self."+attrs['sourceIdentifier'] +".getValue())"))
			elif 'sourceProcess' in attrs:
				self.process_inputs.append(("\'"+attrs['identifier']+"\'", "Outputs[\'"+attrs['sourceProcess']+"\'][\'"+attrs['sourceName']+"\']"))
			else: self.process_inputs.append(("\'"+attrs['identifier']+"\'", attrs['localIdentifier']))
		if name == "output" and self.activ[-1] == "startProcess":
			self.process_outputs.append([attrs['localIdentifier'],attrs['identifier']])

			#if attrs['type']=="literal":
				#self.wps_outputs.append("(\'"+attrs['identifier']+"\', False)")
			#if attrs['type']=="complex":
				#self.wps_outputs.append("(\'"+attrs['identifier']+"\', True)")
		if name == "outputs":
			self.activ.append(name)
		if name =="output" and self.activ[-1] == 'outputs':

			if "sourceProcess" in attrs:
				if attrs['type']=="literal":
					self.final_outputs.append("\t\tself."+attrs['sourceProcess']+"_"+attrs['sourceIdentifier']+".setValue(Outputs[\'"+attrs['sourceProcess']+"\'][\'"+attrs['sourceIdentifier']+"\'])\n" )
					self.result_head+="\t\tself."+attrs['sourceProcess']+'_' + attrs['sourceIdentifier'] +" = self.addLiteralOutput(identifier= \'" + attrs['sourceIdentifier'] + '_' + attrs['sourceProcess'] + "\' , title= \'" + attrs['sourceIdentifier']+"\')\n"
				elif attrs['type'] == "complex":
					self.final_outputs.append("\t\tself."+attrs['sourceProcess']+"_"+attrs['sourceIdentifier']+".setValue(Outputs[\'"+attrs['sourceProcess']+"\'][\'"+attrs['sourceIdentifier']+"\'])\n" )
					self.result_head+="\t\tself."+attrs['sourceProcess']+'_' + attrs['sourceIdentifier'] +" = self.addComplexOutput(identifier= \'" + attrs['sourceIdentifier'] + '_' + attrs['sourceProcess'] + "\' , title= \'" + attrs['sourceIdentifier']+"\')\n"
			else:
				if attrs['type'] == "literal":
					self.final_outputs.append("\t\tself."+attrs['localIdentifier']+".setValue("+attrs['localIdentifier']+")\n" )
					self.result_head+="\t\tself."+attrs['localIdentifier']+" = self.addLiteralOutput(identifier= \'" + attrs['localIdentifier'] + "\' , title= \'" + attrs['localIdentifier']+"\')\n"

				elif attrs['type'] =="complex":
					self.final_outputs.append("\t\tself."+attrs['localIdentifier']+".setValue("+attrs['localIdentifier']+")\n" )
					self.result_head+="\t\tself."+attrs['localIdentifier']+" = self.addComplexOutput(identifier= \'" + attrs['localIdentifier'] + "\' , title= \'" + attrs['localIdentifier']+"\')\n"

	def endElement(self,name):
		if name == "inputs":
			x=self.activ.pop()
		if name == "outputs":
			x=self.activ.pop()
			self.result_head+="\tdef execute(self):\n"
			self.result_head+="\t\tOutputs={}\n"
			self.result_head+="\t\tsys.stdout = open(config.getConfigValue(\"server\",\"logFile\"),'w') \n"

		if name == "try":
			self.trye = False
			self.count_t=0

		if name == "catch":
			self.catch = False
			self.count_t=0

		if name == "startProcess":
			x = self.activ.pop()

			#puts the inputs for the WPS request together
			self.result_body+=self.count_t*"\t"+"\t\tinputs = ["
			for item in self.process_inputs:
				self.result_body+="("+item[0]+","+item[1]+"),"
			self.process_inputs=[]
			self.result_body=self.result_body[:-1]
			self.result_body+="]\n"

			#builds the WPS request
			#Asynchronus request
			if self.synchron == False:
				self.result_body+=self.count_t*"\t"+"\t\texecution = wps.execute(identifier, inputs, output=wps_outputs)\n"
				self.result_body+=self.count_t*"\t"+"\t\tmonitorExecution(execution)\n"
				self.result_body+=self.count_t*"\t"+"\t\texecution.checkStatus(sleepSecs=" + str(self.sleepSecs) + ")\n"

			#Synchronus request
			elif self.synchron == True:
				self.result_body+=self.count_t*"\t"+"\t\texecution = wps.execute(identifier, inputs)\n"

			#process will be executet synchron by default
			self.synchron=True

			self.result_body+=self.count_t*"\t"+"\t\tOutputs[\'"+self.activ_process + "\']={}\n"

			#retrival of complex and literal output
			self.result_body+=self.count_t*"\t"+"\t\tif \"ComplexData\" in description.processOutputs:\n"
			self.result_body+=self.count_t*"\t"+"\t\t\ti=0\n"
			self.result_body+=self.count_t*"\t"+"\t\t\tfor output in execution.processOutputs:\n"
			self.result_body+=self.count_t*"\t"+"\t\t\t\tif description.processOutputs[i].dataType == \'ComplexData\':\n"
			self.result_body+=self.count_t*"\t"+"\t\t\t\t\tOutputs[\'"+ self.activ_process + "'][output.identifier]=output.reference \n"
			self.result_body+=self.count_t*"\t"+"\t\t\t\telse: Outputs[\'"+ self.activ_process + "'][output.identifier]=output.data[0] \n"
			self.result_body+=self.count_t*"\t"+"\t\t\t\ti=i+1\n"

			#retrival of literal output
			self.result_body+=self.count_t*"\t"+"\t\telse:\n"
			self.result_body+=self.count_t*"\t"+"\t\t\tfor output in execution.processOutputs:\n"
			self.result_body+=self.count_t*"\t"+"\t\t\t\tOutputs[\'"+ self.activ_process + "'][output.identifier]=output.data[0] \n"

			for item in self.process_outputs:
				self.result_body+=self.count_t*"\t"+"\t\t" + item[0] +"= Outputs[\'" + self.activ_process + "\' ][\'"+item[1]+ "\']\n"
			self.process_outputs=[]
	def endDocument(self):
		for item in self.final_outputs:
			self.result_tail+=item
		self.result_tail+="\t\tsys.stdout.close()\n"
		self.result_tail+="\t\tsys.stdout = sys.__stdout__\n"
		self.result_tail+="\t\treturn"

		self.result=self.result_head+self.result_body+self.result_tail


# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.

import io
import os
import re

from .ini import combine_fields

__all__ = ["read_toml"]

def parse_toml_str(contents):
    """
    Parse TOML contents using toml
    """
    import toml

    error = None
    manifest = None
    try:
        manifest = toml.loads(contents)
    except toml.TomlDecodeError as pe:
        error = str(pe)
    return error, manifest

def parse_tomlkit_str(contents):
    """
    Parse TOML contents using tomlkit
    """
    import tomlkit
    from tomlkit.exceptions import TOMLKitError

    error = None
    manifest = None
    try:
        manifest = tomlkit.parse(contents)
    except TOMLKitError as pe:
        error = str(pe)
    return error, manifest

def read_toml(
    fp,
    defaults=None,
    default="DEFAULT",
    _comments=None,
    _separators=None,
    strict=True,
    handle_defaults=True,
    document=False,
):
    """
    read a .toml file and return a list of [(section, values)]
    - fp : file pointer or path to read
    - defaults : default set of variables
    - default : name of the section for the default section
    - comments : characters that if they start a line denote a comment
    - separators : strings that denote key, value separation in order
    - strict : whether to be strict about parsing
    - handle_defaults : whether to incorporate defaults into each section
    - document: read TOML with tomlkit and return source in test["document"]
    """

    # variables
    defaults = defaults or {}
    default_section = {}
    sections = []
    if isinstance(fp, str):
        filename = fp
        fp = io.open(fp, encoding="utf-8")
    elif hasattr(fp, "name"):
        filename = fp.name
    else:
        filename = "unknown"
    contents = fp.read()
    inline_comment_rx = re.compile(r"\s#.*$")

    if document:  # Use tomlkit to parse the file contents
        error, manifest = parse_tomlkit_str(contents)
    else:
        error, manifest = parse_toml_str(contents)
    if error:
        raise IOError(f"Error parsing TOML manifest file {filename}: {error}")

    # handle each section of the manifest
    for section in manifest.keys():
        current_section = {}
        for key in manifest[section].keys():
            val = manifest[section][key]
            if isinstance(val, bool):  # must coerce to lowercase string
                if val:
                    val = "true"
                else:
                    val = "false"
            elif isinstance(val, list):
                new_vals = ""
                for v in val:
                    if len(new_vals) > 0:
                        new_vals += os.linesep
                    new_val = str(v).strip()  # coerce to str
                    comment_found = inline_comment_rx.search(new_val)
                    if comment_found:
                        new_val = new_val[0 : comment_found.span()[0]]
                    if " = " in new_val:
                        raise Exception(
                            f"Should not assign in {key} condition for {section}"
                        )
                    new_vals += new_val
                val = new_vals
            else:
                val = str(val).strip()  # coerce to str
                comment_found = inline_comment_rx.search(val)
                if comment_found:
                    val = val[0 : comment_found.span()[0]]
                if " = " in val:
                    raise Exception(
                        f"Should not assign in {key} condition for {section}"
                    )
            current_section[key] = val
        if section.lower() == default.lower():
            default_section = current_section
            # DEFAULT does NOT appear in the output
        else:
            sections.append((section, current_section))

    # merge global defaults with the DEFAULT section
    defaults = combine_fields(defaults, default_section)
    if handle_defaults:
        # merge combined defaults into each section
        sections = [(i, combine_fields(defaults, j)) for i, j in sections]

    if not document:
        manifest = None
    return sections, defaults, manifest

def alphabetize_toml_str(manifest):
    """
    Will take a TOMLkit manifest document (i.e. from a previous invocation
    of read_toml(..., document=True) and accessing the document
    from mp.source_documents[filename]) and return it as a string
    in sorted order by section (i.e. test file name, taking bug ids into consideration).
    """
    import re

    from tomlkit import document, dumps, table
    from tomlkit.items import KeyType, SingleKey

    preamble = ""
    for k, v in manifest.body:
        if k is None:
            preamble += v.as_string()
        else:
            break
    new_manifest = document()
    if "DEFAULT" in manifest:
        new_manifest.add("DEFAULT", manifest["DEFAULT"])
    else:
        new_manifest.add("DEFAULT", table())
    sections = [k for k in manifest.keys() if k != "DEFAULT"]
    regex = r"^([A-Za-z0-9_./-]*)([Bb][Uu][Gg])([-_]*)([0-9]+)([A-Za-z0-9_./-]*)$"
    rx = re.compile(regex)

    def keyfn(k):
        name: str = str(k)
        m = rx.findall(name)
        if len(m) == 1 and len(m[0]) == 5:
            prefix = m[0][0]  # text before "Bug"
            bug = m[0][1]  # the word "Bug"
            underbar = m[0][2]  # underbar or dash (optional)
            num = m[0][3]  # the bug id
            suffix = m[0][4]  # text after the bug id
            name = f"{prefix}{bug.lower()}{underbar}{int(num):09d}{suffix}"
            return name
        return name

    sections = sorted(sections, key=keyfn)
    for k in sections:
        if k.find('"') >= 0:
            section = k
        else:
            section = SingleKey(k, KeyType.Basic)
        new_manifest.add(section, manifest[k])
    manifest_str = dumps(new_manifest)
    # tomlkit fixups
    manifest_str = preamble + manifest_str.replace('"",]', "]")
    while manifest_str.endswith("\n\n"):
        manifest_str = manifest_str[:-1]
    return manifest_str

def add_skip_if(manifest, filename, condition, bug=None):
    """
    Will take a TOMLkit manifest document (i.e. from a previous invocation
    of read_toml(..., document=True) and accessing the document
    from mp.source_documents[filename]) and return it as a string
    in sorted order by section (i.e. test file name, taking bug ids into consideration).
    """
    from tomlkit import array
    from tomlkit.items import Comment, String

    if filename not in manifest:
        raise Exception(f"TOML manifest does not contain section: {filename}")
    keyvals = manifest[filename]
    first = None
    first_comment = ""
    skip_if = None
    if "skip-if" in keyvals:
        skip_if = keyvals["skip-if"]
        if len(skip_if) == 1:
            for e in skip_if._iter_items():
                if not first:
                    first = e
                else:
                    c = e.as_string()
                    if c != ",":
                        first_comment += c
            if skip_if.trivia is not None:
                first_comment += skip_if.trivia.comment[2:]
    mp_array = array()
    if skip_if is None:  # add the first one line entry to the table
        mp_array.add_line(condition, indent="", add_comma=False, newline=False)
        if bug is not None:
            mp_array.comment(bug)
        skip_if = {"skip-if": mp_array}
        keyvals.update(skip_if)
    else:
        if first is not None:
            if first_comment is not None:
                mp_array.add_line(first, indent="  ", comment=first_comment)
            else:
                mp_array.add_line(first, indent="  ")
        if len(skip_if) > 1:
            e_condition = None
            e_comment = None
            for e in skip_if._iter_items():
                if isinstance(e, String):
                    if e_condition is not None:
                        if e_comment is not None:
                            mp_array.add_line(
                                e_condition, indent="  ", comment=e_comment
                            )
                            e_comment = None
                        else:
                            mp_array.add_line(e_condition, indent="  ")
                    if len(e) > 0:
                        e_condition = e
                elif isinstance(e, Comment):
                    e_comment = e.as_string()[3:]
        if bug is not None:
            mp_array.add_line(condition, indent="  ", comment=bug)
        else:
            mp_array.add_line(condition, indent="  ")
        mp_array.add_line("", indent="")  # fixed in write_toml_str
        skip_if = {"skip-if": mp_array}
        del keyvals["skip-if"]
        keyvals.update(skip_if)


class Solution:
    def minMeetingRooms(self, intervals: List[List[int]]) -> int:
        # approach: sort lists of starts an ends, then use two pointers to
        # increment and decrement number of rooms

        st = sorted([i[0] for i in intervals])
        en = sorted([i[1] for i in intervals])

        res, rooms = 0, 0
        i, j = 0, 0

        while i < len(st):
            if st[i] < en[j]:
                i += 1
                rooms += 1
            else:
                j += 1
                rooms -= 1

            res = max(res, rooms)

        return res


import matplotlib.pyplot as plt
import numpy as np
from scipy.linalg import sqrtm

from problemSetting import *

def plotAction(initState, dyn_u):

    x = initState
    traj = []
    for u in dyn_u.reshape(-1,2):
        x = sys_A @ x + sys_B @ u
        traj.append(x)
    traj = np.array(traj)
    plt.plot(traj[:,0],traj[:,1],"-","x")

    N = 36
    for c in collisionList:
        plt.plot(c.x + np.sqrt(c.r2)*np.cos(np.arange(0,(2+1./N)*3.14,2*3.14/N)),
                 c.y + np.sqrt(c.r2)*np.sin(np.arange(0,(2+1./N)*3.14,2*3.14/N)))
    plt.show()

def drawEclips(A,b,c,ax = None):
    if(ax is None):
        ax = plt.gca()

    A,b,c = np.array(A)[:2,:2],np.array(b)[:2],np.array(c)
    sign = np.sign(A[0][0]) # assume A is either pos definate or neg definate
    A,b,c = sign * A, sign * b, sign * c
    A_inv = np.linalg.inv(A)
    c = c - 1/4 * b.T @ A_inv @ b
    b = - 1/2 * A_inv @ b
    R = sqrtm(A_inv)

    N = 36
    points = np.array([np.sqrt(-c) * R @ np.array([np.cos(th),np.sin(th)]) + b for th in np.arange(0,(2+1./N)*3.14,2*3.14/N)])
    ax.plot(points[:,0],points[:,1], "--", label = "CBF boundary")


import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig = plt.figure()

def make_noise_wave(data):
    # 現在描写されているグラフを消去
    plt.cla()
    rand = np.random.randn(50)
    # y軸固定
    plt.ylim(-4, 4)
    im = plt.plot(rand)

ani = animation.FuncAnimation(fig, make_noise_wave, interval=100)
plt.show()


import io
import os
import re

from setuptools import find_packages
from setuptools import setup

def read(filename):
    filename = os.path.join(os.path.dirname(__file__), filename)
    text_type = type(u"")
    with io.open(filename, mode="r", encoding="utf-8") as fd:
        return re.sub(text_type(r":[a-z]+:`~?(.*?)`"), text_type(r"``\1``"), fd.read())

requirements = [
    # use environment.yml
    "numpy"
]

setup(
    name="signal_propagation_plot",
    version="0.0.1",
    url="https://github.com/mehdidc/signal_propagation_plot",
    author="Mehdi Cherti",
    author_email="m.cherti@fz-juelich.de",
    description="Short description",
    long_description=read("README.md"),
    packages=find_packages(exclude=("tests",)),
    install_requires=requirements,
    classifiers=[
        "Programming Language :: Python",
        "Programming Language :: Python :: 3.8",
    ],
)