umur = [2, 5, 5, 6, 7, 8, 10, 12, 4, 1, 9, 7]

umur.sort()

print("Urutan umur dari yang termuda hingga yang tertua: ", umur)

rata2 = sum(umur)/len(umur)

print("\nRata-rata umur sebelum penambahan data adalah ", rata2)

baru = int(input("\nMasukkan umur baru : "))

umur.append(baru)

print("\nUrutan umur dari yang termuda hingga yang tertua terbaru: ", umur)

rata2 = sum(umur)/len(umur)

print("\nRata-rata umur setelah penambahan data adalah ", rata2)


from precession import Precession
from lensing import Lensing
import numpy as np
from pycbc.filter import match
from helper_funcs import Sn
from cobaya.run import run

solar_mass = 4.92624076 * 1e-6 #[solar_mass] = sec
giga_parsec = 1.02927125 * 1e17 #[giga_parsec] = sec
year = 31557600 #[year] = sec

def lnlike(y, ML, theta_tilde, omega_tilde, gamma_P):

    angle_params = {
                'theta_J': 0.,
                'phi_J': 0.,
                'theta_S': np.pi/3,
                'phi_S': 0.
                }

    common_params = {
                'mcz': 20 * solar_mass, 'dist': 1.5 * giga_parsec,
                'eta': 0.25, 'tc': 0.0, 'phi_c': 0.0
                }

    default_precession_params = {
    'theta_S' : angle_params['theta_S'],
    'phi_S' : angle_params['phi_S'],
    'theta_J' : angle_params['theta_J'],
    'phi_J' : angle_params['phi_J'],
    'mcz' : common_params['mcz'],
    'dist': common_params['dist'],
    'eta' : common_params['eta'],
    'tc' : common_params['tc'],
    'phi_c' : common_params['phi_c'],
    'theta_tilde': theta_tilde,
    'omega_tilde': omega_tilde,
    'gamma_P': gamma_P
    }

    default_lensing_params = {
    'theta_S' : angle_params['theta_S'],
    'phi_S' : angle_params['phi_S'],
    'theta_L' : angle_params['theta_J'],
    'phi_L' : angle_params['phi_J'],
    'mcz' : common_params['mcz'],
    'dist': common_params['dist'],
    'eta' : common_params['eta'],
    'tc' : common_params['tc'],
    'phi_c' : common_params['phi_c'],
    'y': y,
    'MLz': ML
    }

    precession_init = Precession(default_precession_params)
    lensing_int = Lensing(default_lensing_params)

    f_cut = Precession(default_precession_params).get_f_cut()
    f_min = 20
    delta_f = 0.25
    f_range = np.arange(f_min, f_cut, delta_f)
    psd = Sn(f_range)

    hP = precession_init.precessing_strain(f_range, delta_f=delta_f)
    hL = lensing_int.lensing_strain(f_range, delta_f=delta_f)

    Match = match(hP, hL, psd)[0]
    return 1 - Match

info = {
    "likelihood": {
        "external": lnlike},
    "params": dict([
        ("y", {
            "prior": {"min": .1, "max": 1.},
            "latex": r"y"}),
	    ("ML", {
            "prior": {"min": 1e2 * solar_mass, "max": 1e5 * solar_mass},
            "latex": r"a"}),
	    ("theta_tilde", {
            "prior": {"min": 1., "max": 8.},
            "latex": r"\tilde{\theta}"}),
	    ("omega_tilde", {
            "prior": {"min": 1., "max": 6.},
            "latex": r"\tilde{\omega}"}),
	    ("gamma_P", {
            "prior": {"min": 0., "max": np.pi},
            "latex": r"\gamma_P"}),

         ] ),

    "sampler": {
        "mcmc": {'max_tries':40000}}, 'output':'/Users/saifali/Desktop/Lensing_precession/chains/' }

updated_info, sampler = run(info)


"""Create quiz_sessions and quiz_session_questions tables

Revision ID: 24695bbcf22d
Revises: 04_4ef9db4e4e1e
Create Date: 2023-07-19 20:41:48.559343

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "05_24695bbcf22d"
down_revision = "04_4ef9db4e4e1e"
branch_labels = None
depends_on = None

def upgrade() -> None:
    op.create_table(
        "quiz_sessions",
        sa.Column("id", sa.UUID(), nullable=False, primary_key=True, index=True),
        sa.Column(
            "created_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.func.now(),
        ),
        sa.Column(
            "last_modified_at",
            sa.DateTime(timezone=True),
            nullable=True,
            onupdate=sa.func.now(),
        ),
        sa.Column("completed_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("score", sa.Integer(), nullable=True),
        sa.Column("user_id", sa.UUID(), nullable=False),
        sa.ForeignKeyConstraint(
            ["user_id"],
            ["users.id"],
        ),
        sa.PrimaryKeyConstraint("id"),
    )
    op.create_table(
        "quiz_session_questions",
        sa.Column("id", sa.UUID(), nullable=False, primary_key=True, index=True),
        sa.Column("question_id", sa.UUID(), nullable=False),
        sa.Column("quiz_session_id", sa.UUID(), nullable=False),
        sa.Column("user_answer", sa.Integer(), nullable=True),
        sa.ForeignKeyConstraint(["question_id"], ["questions.id"], ondelete="CASCADE"),
        sa.ForeignKeyConstraint(
            ["quiz_session_id"], ["quiz_sessions.id"], ondelete="CASCADE"
        ),
        sa.PrimaryKeyConstraint("id"),
    )

def downgrade() -> None:
    op.drop_index(
        op.f("ix_quiz_session_questions_id"), table_name="quiz_session_questions"
    )
    op.drop_table("quiz_session_questions")
    op.drop_index(op.f("ix_quiz_sessions_id"), table_name="quiz_sessions")
    op.drop_table("quiz_sessions")


import argparse
import os

import numpy as np

from keras.models import Sequential
from keras.layers import Input
from keras.layers import GRU
from keras.models import Model
from keras.models import model_from_json
import nsml
from nsml import DATASET_PATH, HAS_DATASET, IS_ON_NSML
from konlpy_set import KinQueryDatasetVer2, preprocess, get_embedding_dim
from util import ManDist
import pickle

# DONOTCHANGE: They are reserved for nsml
# This is for nsml leaderboard
def bind_model(model, config):
    # 학습한 모델을 저장하는 함수입니다.
    def save(dir_name, *args):
        # directory
        os.makedirs(dir_name, exist_ok=True)
        #Keras 모델
        lstm_model = model['lstm_model']
        lstm_json = lstm_model.to_json()
        with open(os.path.join(dir_name, 'lstm_model'), "w") as json_file:
            json_file.write(lstm_json)
        lstm_model.save_weights(os.path.join(dir_name, "lstm_model.h5"))

    # 저장한 모델을 불러올 수 있는 함수입니다.
    def load(dir_name, *args):

        #LSTM 로드
        lstm_model = None
        with open(os.path.join(dir_name, 'lstm_model'), "r") as json_file:
            lstm_model = json_file.read()

        model['lstm_model'] = model_from_json(lstm_model, custom_objects={"ManDist":ManDist})
        model['lstm_model'].load_weights(os.path.join(dir_name, "lstm_model.h5"))

        model['lstm_model'].compile(loss='mean_squared_error', optimizer='adam')

    def infer(raw_data, **kwargs):
        """

        :param raw_data: raw input (여기서는 문자열)을 입력받습니다
        :param kwargs:
        :return:
        """
        # dataset.py에서 작성한 preprocess 함수를 호출하여, 문자열을 벡터로 변환합니다
        gram_y, first_x, second_x = preprocess(raw_data, config.strmaxlen)

        #LSTM Predict
        lstm_model = model['lstm_model']
        lstm_predic = lstm_model.predict([first_x, second_x])

        final_y = lstm_predic

        clipped = np.array(final_y > config.threshold, dtype=np.int)
        # DONOTCHANGE: They are reserved for nsml
        # 리턴 결과는 [(확률, 0 or 1)] 의 형태로 보내야만 리더보드에 올릴 수 있습니다. 리더보드 결과에 확률의 값은 영향을 미치지 않습니다
        return list(zip(final_y.flatten(), clipped.flatten()))

    # DONOTCHANGE: They are reserved for nsml
    # nsml에서 지정한 함수에 접근할 수 있도록 하는 함수입니다.
    nsml.bind(save=save, load=load, infer=infer)

def _batch_loader(iterable, n=1):
    """
    데이터를 배치 사이즈만큼 잘라서 보내주는 함수입니다. PyTorch의 DataLoader와 같은 역할을 합니다

    :param iterable: 데이터 list, 혹은 다른 포맷
    :param n: 배치 사이즈
    :return:
    """
    length = len(iterable)
    for n_idx in range(0, length, n):
        yield iterable[n_idx:min(n_idx + n, length)]

if __name__ == '__main__':

    args = argparse.ArgumentParser()
    # DONOTCHANGE: They are reserved for nsml
    args.add_argument('--mode', type=str, default='train')
    args.add_argument('--pause', type=int, default=0)
    args.add_argument('--iteration', type=str, default="0")

    # User options
    args.add_argument('--output', type=int, default=1)
    args.add_argument('--epochs', type=int, default=500)
    args.add_argument('--batch', type=int, default=2500)
    args.add_argument('--strmaxlen', type=int, default=20)
    args.add_argument('--embedding', type=int, default=8)
    args.add_argument('--threshold', type=float, default=0.5)
    args.add_argument('--n_hidden', type=int, default=15)
    config = args.parse_args()

    if not HAS_DATASET and not IS_ON_NSML:  # It is not running on nsml
        DATASET_PATH = '../sample_data/kin/'

    #analysis_data_feature()

    x = Sequential()
    x.add(GRU(config.n_hidden, input_shape=(config.strmaxlen, get_embedding_dim())))
    shared_model = x

    left_input = Input(shape=(config.strmaxlen, get_embedding_dim()), dtype='float32')
    right_input = Input(shape=(config.strmaxlen, get_embedding_dim()), dtype='float32')

    malstm_distance = ManDist()([shared_model(left_input), shared_model(right_input)])
    lstm_model = Model(inputs=[left_input, right_input], outputs=[malstm_distance])
    lstm_model.compile(loss='mean_squared_error', optimizer='adam')
    bind_model({'lstm_model': lstm_model}, config=config)

    if config.pause:
        nsml.paused(scope=locals())

    if config.mode == 'train':
        dataset = KinQueryDatasetVer2(DATASET_PATH, config.strmaxlen)
        print("loaded complete")
        dataset_len = len(dataset)
        one_batch_size = dataset_len//config.batch
        if dataset_len % config.batch != 0:
            one_batch_size += 1
        # epoch마다 학습을 수행합니다.
        for epoch in range(int(config.iteration) ,config.epochs):
            avg_loss = 0.0
            for i, (ngram_x, first_x, second_x, labels_y) in enumerate(_batch_loader(dataset, config.batch)):
                history = lstm_model.fit([first_x, second_x], labels_y, epochs=1, verbose=0)
                loss = 0
                if history:
                    loss = history.history['loss'][0]

                print('Batch : ', i + 1, '/', one_batch_size,
                         ', BCE in this minibatch: ', float(loss))
                avg_loss += float(loss)
            print('epoch:', epoch, ' train_loss:', float(avg_loss/one_batch_size))
            nsml.report(summary=True, scope=locals(), epoch=epoch, epoch_total=config.epochs,
                        train__loss=float(avg_loss/one_batch_size),  step=epoch)
            # DONOTCHANGE (You can decide how often you want to save the model)
            nsml.save(epoch)

    # # 로컬 테스트 모드일때 사용합니다
    # # 결과가 아래와 같이 나온다면, nsml submit을 통해서 제출할 수 있습니다.
    # # [(0.3, 0), (0.7, 1), ... ]
    elif config.mode == 'test_local':
        lstm_json = lstm_model.to_json()
        with open(os.path.join('./', 'lstm_model'), "w") as json_file:
            json_file.write(lstm_json)
        lstm_model.save_weights(os.path.join('./', "lstm_model.h5"))

        with open(os.path.join('./', 'lstm_model'), "r") as json_file:
            lstm_model = json_file.read()

        load_model = model_from_json(lstm_model, custom_objects={"ManDist": ManDist})
        load_model.load_weights(os.path.join('./', "lstm_model.h5"))

        load_model.compile(loss='mean_squared_error', optimizer='adam')

        with open(os.path.join(DATASET_PATH, 'train/test_data'), 'rt', encoding='utf-8') as f:
            queries = f.readlines()
        res = []
        for batch in _batch_loader(queries, config.batch):
            temp_res = nsml.infer(batch)
            res += temp_res
        print(res)


from urllib.request import Request
from django.shortcuts import redirect, render
from .models import Project

# Create your views here.

def index(request):
    projects = Project.objects.all()[::-1]
    return render(request,'index.html',{'projects':projects})

def add_project(request):
    if request.method == 'POST':
        Project.objects.create(
            title = request.POST['title'],
            des = request.POST['des'],
            tech = request.POST['tech'],
            image = request.FILES['image'] if 'image' in request.FILES else None
        )
        projects = Project.objects.all()[::-1]
        return render(request,'index.html',{'projects':projects,'msg':'Project is Uploaded'})
    projects = Project.objects.all()[::-1]
    return render(request,'index.html',{'projects':projects})

def delete_project(request,pk):
    try:
        project = Project.objects.get(id=pk)
        project.delete()
    except:
        pass
    projects = Project.objects.all()[::-1]
    return render(request,'index.html',{'projects':projects,'msg':'Project Deleted'})

def read_project(request,pk):
    project = Project.objects.get(id=pk)
    return render(request,'read-project.html',{'project':project})

def update_project(request,pk):
    project = Project.objects.get(id=pk)
    if request.method == 'POST':
        project.title = request.POST['title']
        project.des = request.POST['des']
        project.tech = request.POST['tech']
        if 'image' in request.FILES:
            project.image = request.FILES['image']
        project.save()
        projects = Project.objects.all()[::-1]
        return render(request,'index.html',{'projects':projects,'msg':'Project Updated'})
    return render(request,'update-project.html',{'project':project})


import re
import sys

indexRE = re.compile(r'!\d+')

with open(sys.argv[1]) as fin:
    with open(sys.argv[2], 'w') as fout:
        for line in fin:
            # Split on whitespace into "words"
            l = line.split()
            # pop first word (the quoted string) and save for later:
            qstr = l.pop(0)
            # filter remainder to remove zerowidthjoiners and renumber what's left:
            l = [indexRE.sub(f'!{i}', slot) for i,slot in enumerate(filter(lambda x: not x.startswith('[zerowidthjoiner]'), l))]
            l = [indexRE.sub(f'!{i}', slot) for i,slot in enumerate(filter(lambda x: not x.startswith('[uni200D]'), l))]
            # output the results
            print(qstr, ' '.join(l), file=fout)


import pygame
import sys, os
import random
import levels
from levels import Block
from pygame.locals import *
import colorsys
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

class BreakColors:
    BLACK = pygame.Color(0, 0, 0)
    WHITE = pygame.Color(255, 255, 255)
    BLUE = pygame.Color(0, 0, 255)
    RED = pygame.Color(255, 0, 0)
    CYAN = pygame.Color(224, 255, 255)
    LAWNGREEN = pygame.Color(124, 252, 0)
    DARKGRAY = pygame.Color(10, 10, 10)

class Paddle:
    def __init__(self):
        self.rect = pygame.Rect(0, SCREEN_HEIGHT - 32, 160, 16)

class Ball:
    def __init__(self, pos):
        self.reset(pos)

    def update(self):
        self.rect.x += self.dx
        self.rect.y += self.dy

    def reverseY(self):
        self.dy = -self.dy

    def reverseX(self):
        self.dx = -self.dx

    def reset(self, pos):
        self.rect = pygame.Rect(pos, SCREEN_HEIGHT - 64, 20, 20)
        self.dx = 4
        self.dy = -4

class BreakoutGame:
    def __init__(self):
        self.running = False
        pygame.mixer.pre_init(44100, -16, 2, 512)
        pygame.init()
        self.clock = pygame.time.Clock()

        self.screenSize = SCREEN_WIDTH, SCREEN_HEIGHT
        pygame.display.set_caption('Breakout!')
        pygame.mouse.set_visible(False)
        self.screen = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
        self.windowSurf = pygame.display.set_mode(self.screenSize)

        self.font = pygame.font.Font("Fonts/PressStart2P.ttf", 16)

        self.paddle = Paddle()
        self.ball = Ball(SCREEN_WIDTH / 2)

        self.topEdge = pygame.Rect(0, 0, SCREEN_WIDTH, 16)
        self.leftEdge = pygame.Rect(0, 0, 16, SCREEN_HEIGHT)
        self.rightEdge = pygame.Rect(SCREEN_WIDTH - 16, 0, 16, SCREEN_HEIGHT)

        self.boopSound = pygame.mixer.Sound('Sounds/Blip1.wav')
        self.bloopSound = pygame.mixer.Sound('Sounds/Blip2.wav')
        self.explosionSound = pygame.mixer.Sound('Sounds/Explosion.wav')
        self.music = pygame.mixer.Sound('Sounds/music.ogg')

        self.score = 0
        self.ballList = []
        self.colorRot = 0.0
        self.velocityX = 0
        self.lastPaddleRect = self.paddle.rect.copy()
        self.maxVelocity = 16
        self.maxVelocityChange = 8
        self.screenOffsetX = 0
        self.screenOffsetY = 0

    def run(self):
        self.running = True
        self.loadLevel(0)
        self.music.play()
        while self.running:
            for event in pygame.event.get():
                if event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        pygame.event.post(pygame.event.Event(QUIT))
                if event.type == MOUSEMOTION:
                    # update the paddle postition to the mouse position
                    self.mousePosition = event.pos[0]
                    self.mouseRect = Rect(event.pos[0]-4, event.pos[1]-4, 8, 8)
                    self.paddle.rect.x = self.mousePosition - (self.paddle.rect.width / 2)
                    self.velocityX = self.paddle.rect.x - self.lastPaddleRect.x
                    self.lastPaddleRect = self.paddle.rect.copy()
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()

            self.tick()
            self.render()
            pygame.display.update()
            self.clock.tick(60)
            self.colorRot = self.colorRot + 0.05

    def tick(self):
        # update the ball postition
        self.ball.update()
        self.ballList.append(self.ball.rect.copy())
        if len(self.ballList) > 10:
            self.ballList.pop(0)

        # check for collisions with edges
        if self.ball.rect.left <= self.leftEdge.right:
            self.ball.rect.left = self.leftEdge.right
            self.boopSound.play()
            self.screenOffsetX = self.ball.dx
            self.ball.reverseX()
        elif self.ball.rect.right >= self.rightEdge.left:
            self.ball.rect.right = self.rightEdge.left
            self.screenOffsetX = self.ball.dx
            self.boopSound.play()
            self.ball.reverseX()
        if self.ball.rect.top <= self.topEdge.bottom:
            self.ball.rect.top = self.topEdge.bottom
            self.boopSound.play()
            self.screenOffsetY = self.ball.dy
            self.ball.reverseY()

        # check for collision with paddle
        if self.ball.rect.bottom >= self.paddle.rect.top and self.ball.rect.bottom <= SCREEN_HEIGHT and self.ball.rect.centerx in range(
                self.paddle.rect.left, self.paddle.rect.right) and self.ball.rect.centery < self.paddle.rect.centery:
            self.ball.rect.bottom = self.paddle.rect.top
            self.bloopSound.play()
            self.ball.reverseY()
            spin = max(-self.maxVelocityChange, min(self.maxVelocityChange, self.velocityX))
            self.ball.dx = max(-self.maxVelocity, min(self.maxVelocity, self.ball.dx+spin))

        # check for collision with block
        for block in self.blocks:
            if self.ball.rect.colliderect(block.rect):
                overlappingArea = self.ball.rect.clip(block.rect)
                if overlappingArea.width > overlappingArea.height:
                    self.ball.reverseY()
                elif overlappingArea.height > overlappingArea.width:
                    self.ball.reverseX()
                else:
                    self.ball.reverseX()
                    self.ball.reverseY()
                self.blocks.remove(block)
                self.explosionSound.play()
                self.score += 100
                break

        # check for out
        if self.ball.rect.top >= SCREEN_HEIGHT:
            self.lives -= 1
            self.ball.reset(self.paddle.rect.x + (self.paddle.rect.width / 2))

        # check for paddle out
        if self.paddle.rect.left <= self.leftEdge.right:
            self.paddle.rect.left = self.leftEdge.right
        elif self.paddle.rect.right >= self.rightEdge.left:
            self.paddle.rect.right = self.rightEdge.left

        self.screenOffsetX *= 0.9
        self.screenOffsetX *= 0.9

        # check for dead
        if self.lives <= 0:
            self.gameOver()

        # check for won
        if len(self.blocks) <= 0:
            self.win()

    def render(self):
        # print('rendering...') # for testing rendering
        # clear the screen
        self.screen.fill(BreakColors.DARKGRAY)
        #self.background = pygame.image.load(os.path.join('pieces','background.jpg'))
        #self.screen.blit(self.background, (0,0))

        # draw edges
        # Top
        pygame.draw.rect(self.screen, BreakColors.BLACK, self.topEdge)
        # Left
        pygame.draw.rect(self.screen, BreakColors.BLACK, self.leftEdge)
        # Right
        pygame.draw.rect(self.screen, BreakColors.BLACK, self.rightEdge)

        # draw the paddle
        pygame.draw.rect(self.screen, BreakColors.LAWNGREEN, self.paddle.rect)
        pygame.draw.rect(self.screen, BreakColors.WHITE, self.mouseRect)

        # draw the ball
        if self.ball.dx * self.ball.dx + self.ball.dy * self.ball.dy > 32:
            z = 0
            for ballHistory in self.ballList:
                z = z + 1
                r,g,b = colorsys.hsv_to_rgb(self.colorRot + z*0.1, 1, 1)
                pygame.draw.rect(self.screen, pygame.Color(int(r*255), int(g*255), int(b*255)), ballHistory)

        pygame.draw.rect(self.screen, pygame.Color(255, 255, 255), self.ball.rect)

        # draw blocks
        for block in self.blocks:
            pygame.draw.rect(self.screen, block.color, block)
        self.windowSurf.blit(self.screen, (self.screenOffsetX, self.screenOffsetY))

        # draw scoreboard
        scoreSurface = self.font.render("Lives: %i   Score: %i   Level: %i" % (self.lives, self.score, self.level + 1),
                                        False, BreakColors.WHITE)
        self.windowSurf.blit(scoreSurface, (48, 16))

    def gameOver(self):
        messageSurface = self.font.render("Game Over!", False, BreakColors.RED)
        text_rect = messageSurface.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))
        self.windowSurf.blit(messageSurface, text_rect)
        pygame.display.update()
        pygame.time.wait(1000)
        self.level = 0
        self.score = 0
        self.resetGame()

    def win(self):
        messageSurface = self.font.render("CONGRATULATIONS!", False, BreakColors.LAWNGREEN)
        text_rect = messageSurface.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))
        self.windowSurf.blit(messageSurface, text_rect)
        pygame.display.update()
        pygame.time.wait(1000)
        self.level += 1
        self.resetGame()

    def loadLevel(self, levelNum):
        self.lives = 8
        self.level = levelNum
        self.blocks = levels.levels[levelNum].blocks
        self.ball.rect = pygame.Rect(self.paddle.rect.x + (self.paddle.rect.width / 2), SCREEN_HEIGHT - 64, 20, 20)

    def resetGame(self):
        self.lives = 8
        self.loadLevel(self.level)

if __name__ == "__main__":
    game = BreakoutGame()
    game.run()


from collections import defaultdict
import numpy

class Solution:
    def advantageCount(self, A, B):
        """
        :type A: List[int]
        :type B: List[int]
        :rtype: List[int]
        """
        newA = [-1] * len(B)

        A = sorted(A)
        idxB = numpy.argsort(B)
        B = sorted(B)

        indexA = 0
        indexB = len(B)
        available = []

        for i, b in enumerate(B):
            while indexA < len(A) and A[indexA] <= b:
                available.append(A[indexA])
                indexA += 1

            if indexA == len(A):
                indexB = i
                break

            newA[idxB[i]] = A[indexA]
            indexA += 1

        index = 0
        while indexB < len(B):
            newA[idxB[indexB]] = available[index]
            index += 1
            indexB += 1

        return newA


import logging
import os
import re
import signal
import sys
import warnings

# primary public APIs

def configure_logging(logging_config, **kwargs):
    """
    Configure the logging module using the specific configuration object, which
    should be an instance of logging_config.LoggingConfig (usually of a
    subclass).  Any keyword args will be passed to the object's
    configure_logging() method.

    Every entry point should call this method at application startup.
    """
    LoggingManager.logging_config_object = logging_config
    logging_config.configure_logging(**kwargs)

def get_logging_manager(manage_stdout_and_stderr=False, redirect_fds=False):
    """
    Create a LoggingManager that's managing sys.stdout and sys.stderr.

    Every entry point that wants to capture stdout/stderr and/or use
    LoggingManager to manage a stack of destinations should call this method
    at application startup.
    """
    if redirect_fds:
        manager = FdRedirectionLoggingManager()
    else:
        manager = LoggingManager()
    if manage_stdout_and_stderr:
        manager.manage_stdout()
        manager.manage_stderr()
    return manager

# implementation follows

logger = logging.getLogger()

def _current_handlers():
    return set(logger.handlers)

_caller_code_to_skip_in_logging_stack = set()

def do_not_report_as_logging_caller(func):
    """Decorator to annotate functions we will tell logging not to log."""
    # These are not the droids you are looking for.
    # You may go about your business.
    _caller_code_to_skip_in_logging_stack.add(func.func_code)
    return func

# Copied from Python 2.4 logging/__init__.py Logger.findCaller and enhanced.
# The logging code remains the same and compatible with this monkey patching
# through at least Python version 2.6.2.
def _logging_manager_aware_logger__find_caller(unused):
    """
    Find the stack frame of the caller so that we can note the source
    file name, line number and function name.
    """
    f = sys._getframe(2).f_back
    rv = "(unknown file)", 0, "(unknown function)"
    while hasattr(f, "f_code"):
        co = f.f_code
        filename = os.path.normcase(co.co_filename)
        if filename == logging._srcfile:
            f = f.f_back
            continue
        # START additional code.
        if co in _caller_code_to_skip_in_logging_stack:
            f = f.f_back
            continue
        # END additional code.
        rv = (filename, f.f_lineno, co.co_name)
        break
    return rv

if sys.version_info[:2] > (2, 7):
    warnings.warn('This module has not been reviewed for Python %s' %
                  sys.version)

# Monkey patch our way around logging's design...
_original_logger__find_caller = logging.Logger.findCaller
logging.Logger.findCaller = _logging_manager_aware_logger__find_caller

class LoggingFile(object):

    """
    File-like object that will receive messages pass them to the logging
    infrastructure in an appropriate way.
    """

    def __init__(self, prefix='', level=logging.DEBUG,
                 logger=logging.getLogger()):
        """
        :param prefix - The prefix for each line logged by this object.
        """

        self._prefix = prefix
        self._level = level
        self._buffer = []
        self._logger = logger

    @do_not_report_as_logging_caller
    def write(self, data):
        """"
        Writes data only if it constitutes a whole line. If it's not the case,
        store it in a buffer and wait until we have a complete line.
        :param data - Raw data (a string) that will be processed.
        """
        # splitlines() discards a trailing blank line, so use split() instead
        data_lines = data.split('\n')
        if len(data_lines) > 1:
            self._buffer.append(data_lines[0])
            self._flush_buffer()
        for line in data_lines[1:-1]:
            self._log_line(line)
        if data_lines[-1]:
            self._buffer.append(data_lines[-1])

    @do_not_report_as_logging_caller
    def writelines(self, lines):
        """"
        Writes itertable of lines

        :param lines: An iterable of strings that will be processed.
        """
        for data in lines:
            self.write(data)

    @do_not_report_as_logging_caller
    def _log_line(self, line):
        """
        Passes lines of output to the logging module.
        """
        self._logger.log(self._level, self._prefix + line)

    @do_not_report_as_logging_caller
    def _flush_buffer(self):
        if self._buffer:
            self._log_line(''.join(self._buffer))
            self._buffer = []

    @do_not_report_as_logging_caller
    def flush(self):
        self._flush_buffer()

    def isatty(self):
        return False

class SortingLoggingFile(LoggingFile):

    """
    File-like object that will receive messages and pass them to the logging
    infrastructure. It decides where to pass each line by applying a regex
    to it and seeing which level it matched.
    """

    def __init__(self, prefix='', level_list=[('ERROR', logging.ERROR),
                                              ('WARN', logging.WARN), ('INFO', logging.INFO),
                                              ('DEBUG', logging.DEBUG)], logger=logging.getLogger()):
        super(SortingLoggingFile, self).__init__(prefix=prefix, logger=logger)
        self._level_list = [(re.compile(x), y) for x, y in level_list]

    @do_not_report_as_logging_caller
    def _log_line(self, line):
        for pattern, level in self._level_list:
            if pattern.search(line):
                self._logger.log(level, self._prefix + line)
                break
        else:
            self._logger.log(logging.ERROR, 'UNMATCHED_LOG_LEVEL: ' +
                             self._prefix + line)

class _StreamManager(object):

    """
    Redirects all output for some output stream (normally stdout or stderr) to
    the logging module by replacing the file objects with a new LoggingFile
    that calls logging.log().
    """

    def __init__(self, stream, level, stream_setter):
        """
        :param stream: stream object to manage
        :param level: level at which data written to the stream will be logged
        :param stream_setter: function accepting a stream object that will
                replace the given stream in its original location.
        """
        self._stream = stream
        self._level = level
        self._stream_setter = stream_setter
        self._logging_stream = None

    def _replace_with_logger(self):
        self._logging_stream = LoggingFile(level=self._level)
        self._stream_setter(self._logging_stream)

    def _restore_stream(self):
        self._stream_setter(self._stream)

    def flush(self):
        self._logging_stream.flush()

    def start_logging(self):
        """Start directing the stream to the logging module."""
        self._replace_with_logger()

    def stop_logging(self):
        """Restore the stream to its original settings."""
        self._restore_stream()

    def on_push_context(self, context):
        """
        Called when the logging manager is about to push a new context onto the
        stack and has changed logging settings.  The StreamHandler can modify
        the context to be saved before returning.
        """
        pass

    def on_restore_context(self, context):
        """
        Called when the logging manager is restoring a previous context.
        """
        pass

class LoggingManager(object):

    """
    Manages a stack of logging configurations, allowing clients to conveniently
    add and remove logging destinations.  Also keeps a list of StreamManagers
    to easily direct streams into the logging module.
    """

    STREAM_MANAGER_CLASS = _StreamManager

    logging_config_object = None

    def __init__(self):
        """
        This class should not ordinarily be constructed directly (other than in
        tests).  Use the module-global factory method get_logging_manager()
        instead.
        """
        if self.logging_config_object is None:
            raise RuntimeError('You must call configure_logging() before this')

        # _context_stack holds a stack of context dicts.  Each context dict
        # contains:
        # * old_handlers: list of registered logging Handlers
        # contexts may also be extended by _StreamHandlers
        self._context_stack = []
        self._streams = []
        self._started = False

    def manage_stream(self, stream, level, stream_setter):
        """
        Tells this manager to manage the given stream.  All data written to the
        stream will be directed to the logging module instead.  Must be called
        before start_logging().

        :param stream: stream to manage
        :param level: level to log data written to this stream
        :param stream_setter: function to set the stream to a new object
        """
        if self._started:
            raise RuntimeError('You must call this before start_logging()')
        self._streams.append(self.STREAM_MANAGER_CLASS(stream, level,
                                                       stream_setter))

    def _sys_stream_setter(self, stream_name):
        assert stream_name in ('stdout', 'stderr'), stream_name

        def set_stream(file_object):
            setattr(sys, stream_name, file_object)
        return set_stream

    def manage_stdout(self):
        self.manage_stream(sys.stdout, logging.INFO,
                           self._sys_stream_setter('stdout'))

    def manage_stderr(self):
        self.manage_stream(sys.stderr, self.logging_config_object.stderr_level,
                           self._sys_stream_setter('stderr'))

    def start_logging(self):
        """
        Begin capturing output to the logging module.
        """
        for stream_manager in self._streams:
            stream_manager.start_logging()
        self._started = True

    def stop_logging(self):
        """
        Restore output to its original state.
        """
        while self._context_stack:
            self._pop_context()

        for stream_manager in self._streams:
            stream_manager.stop_logging()

        self._started = False

    def _clear_all_handlers(self):
        for handler in _current_handlers():
            logger.removeHandler(handler)

    def _get_context(self):
        return {'old_handlers': _current_handlers()}

    def _push_context(self, context):
        for stream_manager in self._streams:
            stream_manager.on_push_context(context)
        self._context_stack.append(context)

    def _flush_all_streams(self):
        for stream_manager in self._streams:
            stream_manager.flush()

    def _add_log_handlers(self, add_handlers_fn):
        """
        Modify the logging module's registered handlers and push a new context
        onto the stack.
        :param add_handlers_fn: function to modify the registered logging
        handlers. Accepts a context dictionary which may be modified.
        """
        self._flush_all_streams()
        context = self._get_context()

        add_handlers_fn(context)

        self._push_context(context)

    class _TaggingFormatter(logging.Formatter):

        """
        Delegates to a given formatter, but prefixes each line of output with a
        tag.
        """

        def __init__(self, base_formatter, tag):
            self.base_formatter = base_formatter
            prefix = tag + ' : '
            self._fmt = base_formatter._fmt.replace('%(message)s',
                                                    prefix + '%(message)s')
            self.datefmt = base_formatter.datefmt

    def _add_tagging_formatter(self, tag):
        for handler in _current_handlers():
            tagging_formatter = self._TaggingFormatter(handler.formatter, tag)
            handler.setFormatter(tagging_formatter)

    def _do_redirect(self, stream=None, filename=None, level=None,
                     clear_other_handlers=False):
        """
        :param clear_other_handlers - if true, clear out all other logging
        handlers.
        """
        assert bool(stream) != bool(filename)  # xor
        if not self._started:
            raise RuntimeError('You must call start_logging() before this')

        def add_handler(context):
            if clear_other_handlers:
                self._clear_all_handlers()

            if stream:
                handler = self.logging_config_object.add_stream_handler(stream)
            else:
                handler = self.logging_config_object.add_file_handler(filename)

            if level:
                handler.setLevel(level)

        self._add_log_handlers(add_handler)

    def redirect(self, filename):
        """Redirect output to the specified file"""
        self._do_redirect(filename=filename, clear_other_handlers=True)

    def redirect_to_stream(self, stream):
        """Redirect output to the given stream"""
        self._do_redirect(stream=stream, clear_other_handlers=True)

    def tee_redirect(self, filename, level=None):
        """Tee output to the specified file"""
        self._do_redirect(filename=filename, level=level)

    def tee_redirect_to_stream(self, stream):
        """Tee output to the given stream"""
        self._do_redirect(stream=stream)

    def tee_redirect_debug_dir(self, debug_dir, log_name=None, tag=None):
        """
        Tee output to a full new set of debug logs in the given directory.
        """
        def add_handlers(context):
            if tag:
                self._add_tagging_formatter(tag)
                context['tag_added'] = True
            self.logging_config_object.add_debug_file_handlers(
                debug_dir, log_name=log_name)
        self._add_log_handlers(add_handlers)

    def _restore_context(self, context):
        for stream_handler in self._streams:
            stream_handler.on_restore_context(context)

        # restore logging handlers
        old_handlers = context['old_handlers']
        for handler in _current_handlers() - old_handlers:
            handler.close()
        self._clear_all_handlers()
        for handler in old_handlers:
            logger.addHandler(handler)

        if 'tag_added' in context:
            for handler in _current_handlers():
                tagging_formatter = handler.formatter
                handler.setFormatter(tagging_formatter.base_formatter)

    def _pop_context(self):
        self._flush_all_streams()
        context = self._context_stack.pop()
        self._restore_context(context)

    def undo_redirect(self):
        """
        Undo the last redirection (that hasn't yet been undone).

        If any subprocesses have been launched since the redirection was
        performed, they must have ended by the time this is called.  Otherwise,
        this will hang waiting for the logging subprocess to end.
        """
        if not self._context_stack:
            raise RuntimeError('No redirects to undo')
        self._pop_context()

    def restore(self):
        """
        Same as undo_redirect().  For backwards compatibility with
        fd_stack.
        """
        self.undo_redirect()

class _FdRedirectionStreamManager(_StreamManager):

    """
    Like StreamManager, but also captures output from subprocesses by modifying
    the underlying file descriptors.

    For the underlying file descriptors, we spawn a subprocess that writes all
    input to the logging module, and we point the FD to that subprocess.  As a
    result, every time we redirect output we need to spawn a new subprocess to
    pick up the new logging settings (without disturbing any existing processes
    using the old logging subprocess).

    If, one day, we could get all code using utils.run() and friends to launch
    subprocesses, we'd no longer need to handle raw FD output, and we could
    get rid of all this business with subprocesses.  Another option would be
    to capture all stray output to a single, separate destination.
    """

    def __init__(self, stream, level, stream_setter):
        if not hasattr(stream, 'fileno'):
            # with fake, in-process file objects, subprocess output won't be
            # captured. this should never happen in normal use, since the
            # factory methods will only pass sys.stdout and sys.stderr.
            raise ValueError("FdRedirectionLoggingManager won't work with "
                             "streams that aren't backed by file "
                             "descriptors")

        super(_FdRedirectionStreamManager, self).__init__(stream, level,
                                                          stream_setter)
        self._fd = stream.fileno()
        self._fd_copy_stream = None

    def _point_stream_handlers_to_copy(self):
        """
        point logging StreamHandlers that point to this stream to a safe
        copy of the underlying FD. otherwise, StreamHandler output will go
        to the logging subprocess, effectively getting doubly logged.
        """
        fd_copy = os.dup(self._fd)
        self._fd_copy_stream = os.fdopen(fd_copy, 'w')
        self._redirect_logging_stream_handlers(self._stream,
                                               self._fd_copy_stream)

    def _restore_stream_handlers(self):
        """ point logging StreamHandlers back to the original FD """
        self._redirect_logging_stream_handlers(self._fd_copy_stream,
                                               self._stream)
        self._fd_copy_stream.close()

    def _redirect_logging_stream_handlers(self, old_stream, new_stream):
        """
        Redirect all configured logging StreamHandlers pointing to
        old_stream to point to new_stream instead.
        """
        for handler in _current_handlers():
            points_to_stream = (isinstance(handler, logging.StreamHandler) and
                                hasattr(handler.stream, 'fileno') and
                                handler.stream.fileno() == old_stream.fileno())
            if points_to_stream:
                logger.removeHandler(handler)
                handler.close()  # doesn't close the stream, just the handler

                new_handler = logging.StreamHandler(new_stream)
                new_handler.setLevel(handler.level)
                new_handler.setFormatter(handler.formatter)
                for log_filter in handler.filters:
                    new_handler.addFilter(log_filter)
                logger.addHandler(new_handler)

    def start_logging(self):
        super(_FdRedirectionStreamManager, self).start_logging()
        self._point_stream_handlers_to_copy()

    def stop_logging(self):
        super(_FdRedirectionStreamManager, self).stop_logging()
        self._restore_stream_handlers()

    def _spawn_logging_subprocess(self):
        """
        Spawn a subprocess to log all input to the logging module with the
        current settings, and direct output to it.
        """
        read_end, write_end = os.pipe()
        pid = os.fork()
        if pid:  # parent
            os.close(read_end)
            os.dup2(write_end, self._fd)  # point FD to the subprocess
            os.close(write_end)
            return pid
        else:  # child
            try:
                os.close(write_end)
                # ensure this subprocess doesn't hold any pipes to others
                os.close(1)
                os.close(2)
                self._run_logging_subprocess(read_end)  # never returns
            except Exception:
                # don't let exceptions in the child escape
                try:
                    logging.exception('Logging subprocess died:')
                finally:
                    os._exit(1)

    def _run_logging_subprocess(self, read_fd):
        """
        Always run from a subprocess.  Read from read_fd and write to the
        logging module until EOF.
        """
        signal.signal(signal.SIGTERM, signal.SIG_DFL)  # clear handler
        input_file = os.fdopen(read_fd, 'r')
        for line in iter(input_file.readline, ''):
            logging.log(self._level, line.rstrip('\n'))
        os._exit(0)

    def _context_id(self):
        return '%s_context' % id(self)

    def on_push_context(self, context):
        # adds a context dict for this stream, $id_context, with the following:
        # * old_fd: FD holding a copy of the managed FD before launching a new
        #   subprocess.
        # * child_pid: PID of the logging subprocess launched
        fd_copy = os.dup(self._fd)
        child_pid = self._spawn_logging_subprocess()
        my_context = {'old_fd': fd_copy, 'child_pid': child_pid}
        context[self._context_id()] = my_context

    def on_restore_context(self, context):
        my_context = context[self._context_id()]

        # shut down subprocess
        child_pid = my_context['child_pid']
        try:
            os.close(self._fd)
            os.waitpid(child_pid, 0)
        except OSError:
            logging.exception('Failed to cleanly shutdown logging subprocess:')

        # restore previous FD
        old_fd = my_context['old_fd']
        os.dup2(old_fd, self._fd)
        os.close(old_fd)

class FdRedirectionLoggingManager(LoggingManager):

    """
    A simple extension of LoggingManager to use FdRedirectionStreamManagers,
    so that managed streams have their underlying FDs redirected.
    """

    STREAM_MANAGER_CLASS = _FdRedirectionStreamManager

    def start_logging(self):
        super(FdRedirectionLoggingManager, self).start_logging()
        # spawn the initial logging subprocess
        self._push_context(self._get_context())

    def undo_redirect(self):
        # len == 1 would mean only start_logging() had been called (but no
        # redirects had occurred)
        if len(self._context_stack) < 2:
            raise RuntimeError('No redirects to undo')
        super(FdRedirectionLoggingManager, self).undo_redirect()


"""
An image is represented by an m x n integer grid image where image[i][j] represents the pixel value of the image.

You are also given three integers sr, sc, and newColor. You should perform a flood fill on the image starting from the pixel image[sr][sc].

To perform a flood fill, consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same color), and so on. Replace the color of all of the aforementioned pixels with newColor.

Return the modified image after performing the flood fill.
"""

class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:

        if image[sr][sc] == newColor:
            return image
        self.fill(image, sr, sc, image[sr][sc], newColor)
        return image

    def fill(self, image, r, c, initial, meow):
        if r<0 or r >= len(image) or c<0 or c>= len(image[0]) or image[r][c] != initial:
            return
        image[r][c] = meow
        self.fill(image,r+1,c, initial, meow)
        self.fill(image,r-1,c, initial, meow)
        self.fill(image,r,c+1, initial, meow)
        self.fill(image,r,c-1, initial, meow)


import os
from pathlib import Path

from crispy_forms.utils import render_crispy_form
from django.test.html import Element, parse_html

TEST_DIR = os.path.dirname(os.path.abspath(__file__))

def contains_partial(haystack, needle, ignore_needle_children=False):
    """Search for a html element with at least the corresponding elements
    (other elements may be present in the matched element from the haystack)
    """
    if not isinstance(haystack, Element):
        haystack = parse_html(haystack)
    if not isinstance(needle, Element):
        needle = parse_html(needle)

    if len(needle.children) > 0 and not ignore_needle_children:
        raise NotImplementedError(
            "contains_partial does not check needle's children:%s"
            % str(needle.children)
        )

    if needle.name == haystack.name and set(needle.attributes).issubset(
        haystack.attributes
    ):
        return True
    return any(
        contains_partial(child, needle, ignore_needle_children=ignore_needle_children)
        for child in haystack.children
        if isinstance(child, Element)
    )

def parse_expected(expected_file):
    test_file = Path(TEST_DIR) / "results" / expected_file
    with open(test_file) as f:
        return parse_html(f.read())

def parse_form(form):
    html = render_crispy_form(form)
    return parse_html(html)


import sys
import os
import pickle
import networkx as nx
import subprocess
from cere.graph_utils import *
from cere import cere_configure
from cere import cere_check_matching
import logging
from cere import vars as var
from cere import utils

logger = logging.getLogger('ILP selector')

def update(args):
    binary_cmd = cere_configure.cere_config["run_cmd"]
    build_cmd = cere_configure.cere_config["build_cmd"]
    args.regions_file = "{0}/loops".format(var.CERE_REPLAY_PATH)
    args.region = None

    logger.info("Start graph updating")
    graph = load_graph()
    if graph == None:
        logger.critical("No graph to load. Did you run cere profile?")
        return False

    while(1):
        graph = load_graph()

        newLoopsToTest = False
        with open(args.regions_file, 'w') as f:
            for n, d in graph.nodes(data=True):
                if d['_coverage'] < args.min_coverage: d['_small'] = True
                if d['_valid'] and not d['_small'] and not d['_tested']:
                    newLoopsToTest = True
                    d['_to_test']=True
                    f.write(d['_name']+"\n")

        plot(graph)
        save_graph(graph)
        if not newLoopsToTest:
            break
        else:
            cere_check_matching.run(args)

    return True


from typing import List

class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        d = {}
        for i in range(len(nums)):
            if nums[i] not in d:
                d[nums[i]] = 1
            else:
                d[nums[i]] += 1
            if d[nums[i]] == (len(nums) + 1) // 2:
                return nums[i]

print(Solution().majorityElement([2,2,1,1,1,2,2]))


import json
from Framework.task import Task
from Framework.tasks.checkpointtask import DataCheckpointTask
import time
import os

class Pipeline:

    def __init__(self, *tasks: Task, **kwargs):
        self.tasks = tasks
        self.data = {
            "output": {}
        }

        self._process_kwargs(kwargs)

        for task in self.tasks:
            task.create_resource_path = self.create_resource_path

        self.checkpoints = filter(lambda t: type(t) == DataCheckpointTask, self.tasks)
        self._setup_checkpoints()
        if not self.from_start:
            self._check_checkpoints()

        self.set_resource_path_func(self.tasks)

    def _process_kwargs(self, kwargs):
        if "output_file" in kwargs:
            self.output_file = kwargs["output_file"]
        else:
            self.output_file = "output.json"

        if "pipeline_path" in kwargs:
            self.pipeline_path = kwargs["pipeline_path"]
        else:
            self.pipeline_path = ""

        if "from_start" in kwargs:
            self.from_start = kwargs["from_start"]
        else:
            self.from_start = False

        def join_path(file: str):
            return os.path.join(self.pipeline_path, file)

        self.create_resource_path = join_path

    def _setup_checkpoints(self):
        cnt = 1
        for chp in self.checkpoints:
            chp.checkpoint_num = cnt
            cnt += 1

    def _check_checkpoints(self):
        for i in range(len(self.tasks)-1, 0, -1):
            task = self.tasks[i]
            if type(task) == DataCheckpointTask and task.does_checkpoint_file_exist():
                self.data = task.load_checkpoint()
                self.tasks = self.tasks[i+1:]
                return

    def set_resource_path_func(self, tasks: list):
        for task in tasks:
            task.set_resource_path_func(self.create_resource_path)
            if hasattr(task, "tasks"):
                self.set_resource_path_func(task.tasks)

    def run(self):
        """Process tasks and checkpoints"""

        start = time.perf_counter()
        print(start)

        for task in self.tasks:
            task.process(self.data)
        self.write_output()

        diff = time.perf_counter() - start
        print(f"The pipeline took {diff:.2} second(s) to complete.")

    def write_output(self):
        if len(self.data["output"].keys()) > 0:
            with open(self.create_resource_path(self.output_file), "w") as f:
                f.write(json.dumps(self.data["output"]))


import torch
import pytorch_lightning as pl
from torch.utils.data import DataLoader
import torch.nn.functional as F
from torch import nn
#import torchvision as tv
from NucleicNet import Burn, Fuel
import torchmetrics
from NucleicNet.Burn import Catalogue_Activation
#from torchmetrics.functional import accuracy
import NucleicNet.Burn.T1
import NucleicNet.Burn.LRS
import NucleicNet.Burn.DA
# ==================================
# Naive adaptor
# ==================================
class B1hw_NaiveRepeatB3hwFcLogits(pl.LightningModule):
    def __init__(self,
                    model   = None, # tv.models.resnet18(nested_module = True),
                    loss    = nn.CrossEntropyLoss(),
                    n_channel = 3,
                    n_class = 10):
        super().__init__()
        if help:

            """
            # NOTE This is a naive 'working' handle to take 1-D tensor forged to (b,1,h,w)
            #      and further forged to (b,3,h,w) by simply repeating the vector
            #      The critique here is that it does not handle batch-normalisation correctly,
            #      because the meaning of color channel mismatches. (it 'smudges' all the features)
            #      This maybe considered the toy model to be compared for debugging purpose.
            #      However, it also offers a template to construct and model with a FcLogit output
            # NOTE The "model" flag assumes the last layer being named 'fc' for fully connected
            """

        self.n_channel = n_channel
        self.n_class = n_class
        self.nested_module = model

        # ==========================================
        # Construct a fc "suffix" adapter
        # ==========================================

        for _, lastfc in self.nested_module.named_modules():
            pass
        if str(lastfc).startswith("Linear"):
            fcsize = int(str(lastfc).split(", out_features=")[-1].split(",")[0])
            fcsize_infeature = int(str(lastfc).split("in_features=")[-1].split(",")[0])
        else:
            raise KeyError("ABORTED. Provided nested_module model does not end with a fc layer.")

        #self.suffixadaptor = nn.Linear(fcsize, self.n_class, bias=True)
        self.nested_module.fc = nn.Linear(fcsize_infeature, self.n_class, bias=True)

        # NOTE The FC output imply logits. This should be a loss accepting logit
        self.loss = loss
        self.automatic_optimization = True
    def forward(self, x):
        #print(x.shape)
        x = Fuel.T1.B1hw_Bnhw(x, n_channel = self.n_channel) # NOTE prefixadaptor
        x = self.nested_module(x)
        #x = self.suffixadaptor(x)
        return x

    def training_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        loss = self.loss(logits, y)
        ACC = torchmetrics.functional.accuracy(logits, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        PR = torchmetrics.functional.precision_recall(logits, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        self.log('train_precision', PR[0])
        self.log('train_recall', PR[1])
        self.log('train_acc', ACC)
        self.log('train_loss_s', loss, prog_bar=True)
        return loss

    def validation_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        CE = nn.CrossEntropyLoss()
        loss = CE(logits, y) #self.loss(logits, y) # NOTE Validate without the random
        self.log('val_loss_s', loss, prog_bar=True)
        self.log("val_loss", loss)
        ACC = torchmetrics.functional.accuracy(logits, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        PR = torchmetrics.functional.precision_recall(logits, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        self.log('val_acc', ACC)
        self.log('val_recall', PR[1])
        self.log('val_precision', PR[0])
        return loss

    def predict_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        p = torch.softmax(logits, dim=1)
        return p

    #lr_scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[5,150,300,600,1200,], gamma=0.1)
    def configure_optimizers(self):
        optimizer = torch.optim.AdamW(self.parameters(), lr=1e-4)
        lr_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=100, factor=0.99,
                            verbose=True, threshold = 1e-5, min_lr= 1e-6, cooldown = 1000)
        return {
                "optimizer": optimizer,
                "lr_scheduler": {
                    "scheduler": lr_scheduler,
                    'reduce_on_plateau': True,
                    "interval": "step",
                    "frequency": 1,
                    "monitor": "train_loss_s",
                # If "monitor" references validation metrics, then "frequency" should be set to a
                # multiple of "trainer.check_val_every_n_epoch".
            },
        }

# =================================
# Logit Template
# =================================
class B1hw_FcLogits(pl.LightningModule):
    def __init__(self, #learning_rate,
                    model   = None,
                    User_Loss    = "CrossEntropyLoss", #nn.CrossEntropyLoss(),
                    hw_product = 480,
                    adaptive2dpool = (3,40),
                    #User_Activation = 'gelu',

                    n_class = 10,
                    BiasInSuffixFc = True,
                    AddMultiLabelSoftMarginLoss = False, # NOTE Worsen stuff?
                    User_lr = 1e-05,
                    User_AdamW_weight_decay = 1e-2,
                    User_min_lr = 1e-6,
                    User_CooldownInterval = 753,
                    User_LrScheduler = 'CosineAnnealingLR',
                    User_ShiftLrRatio = 0.5,
                    # NOTE basic overfit
                    User_Dropoutp = 0.5,
                    User_AddL1 = 0.9,
                    User_NoiseX = 0.1,
                    User_NoiseY = 0.1,
                    User_NoiseZ = 0.1,
                    device = torch.device('cuda'),
                    ManualInitiation = False,
                    User_Mixup = False,
                    User_LabelSmoothing = 0.0,
                    User_NeighborLabelSmoothAngstrom = 1.5,
                    User_InputDropoutp = 0.1,
                    User_FocalLossAlpha = 0.25,
                    User_FocalLossGamma = 2,
                    **kwargs,
        ):
        super().__init__()
        if help:

            """
            # NOTE This is a template to take (b,1,h,w)
            #      The user-defined model has to be a torch functional with batch normalisation defined correctly.
            #      the last layer will be flattened to be fed to a Fc for logit traiinng.
            """
        #self.learning_rate = learning_rate
        if User_lr is not None:
            self.learning_rate = User_lr
        self.n_class = n_class
        self.nested_module = model
        self.hw_product  = hw_product
        try:
            self.User_Activation = model.User_Activation
        except:
            self.User_Activation = 'relu'

        self.User_CooldownInterval = User_CooldownInterval
        self.User_min_lr = User_min_lr
        self.User_AdamW_weight_decay = User_AdamW_weight_decay
        self.User_LrScheduler = User_LrScheduler
        self.User_Dropoutp = User_Dropoutp
        self.AddMultiLabelSoftMarginLoss = AddMultiLabelSoftMarginLoss
        self.User_AddL1 = User_AddL1
        self.User_ShiftLrRatio = User_ShiftLrRatio
        self.User_NoiseX = User_NoiseX
        self.User_NoiseY = User_NoiseY
        self.User_Mixup = User_Mixup
        self.User_LabelSmoothing = User_LabelSmoothing
        self.User_NoiseZ = User_NoiseZ
        self.User_NeighborLabelSmoothAngstrom = User_NeighborLabelSmoothAngstrom
        self.User_InputDropoutp = User_InputDropoutp
        self.User_FocalLossAlpha = User_FocalLossAlpha
        self.User_FocalLossGamma = User_FocalLossGamma

        #self.AddL2 = AddL2
        self.device_ = device

        # Saving all entered hparam above
        self.save_hyperparameters(ignore = ["model_params", 'device', 'model', 'loss'])
        # ==========================================
        # Construct a fc "suffix" adapter
        # ==========================================
        self.prefix_layerD = nn.Sequential(
            nn.Dropout(p=self.User_InputDropoutp,inplace=False)
        )
        # Mapping to classification output
        self.suffix_layerA = nn.Sequential(
            #nn.AdaptiveAvgPool2d((adaptive2dpool[0],adaptive2dpool[1])), # NOTE referencing torchvision's implemetation a pooling layer can be addded
            nn.Flatten(start_dim=1, end_dim=- 1),
        )

        self.suffix_layerD = nn.Sequential(
                #nn.Dropout(p=self.User_Dropoutp, inplace=False),
                #NucleicNet.Burn.T1.NoisyLinear(self.hw_product, self.hw_product, bias=BiasInSuffixFc, sigma_init= self.User_NoiseZ),
                nn.Dropout(p=self.User_Dropoutp, inplace=False),
                nn.Linear(self.hw_product, self.hw_product, bias=BiasInSuffixFc),
                nn.Dropout(p=self.User_Dropoutp, inplace=False),
        )

        self.suffix_layerZ = nn.Sequential(
            nn.Linear(self.hw_product, self.n_class, bias=False)

        )

        if ManualInitiation:
            self._init_params()

        self.User_Loss = User_Loss # This is a string
        self.CatalogueLoss = {
            "CrossEntropyLoss" : nn.CrossEntropyLoss(label_smoothing=self.User_LabelSmoothing),
            "MixupSoftmaxLoss": NucleicNet.Burn.DA.MixupSoftmaxLoss(class_weights = None, reduction = 'mean', label_smooth_eps = self.User_LabelSmoothing),
            "SigmoidalFocalLoss": NucleicNet.Burn.T1.SigmoidalFocalLoss(alpha = self.User_FocalLossAlpha, gamma = self.User_FocalLossGamma,label_smoothing = self.User_LabelSmoothing),
            "MultiLabelSoftMarginLoss": nn.MultiLabelSoftMarginLoss(weight=None, size_average=None, reduce=None, reduction='mean')
        }

        self.loss = self.CatalogueLoss[self.User_Loss]
        self.automatic_optimization = True

    def forward(self, x):
        x = self.prefix_layerD(x)
        x = self.nested_module(x)
        # NOTE We cannot standardize the last layer as it will severely hurt performance. Adding noise here can be dangerous
        #if (self.training) & (self.User_NoiseZ > 0.0):
        #    x += self.User_NoiseZ *  torch.randn(x.shape, device = self.device_)# NOTE Noise added in training

        x = self.suffix_layerA(x)
        if self.User_Dropoutp > 0.0:
            x = self.suffix_layerD(x)
        x = self.suffix_layerZ(x)

        return x

    def training_step(self, batch, batch_idx):

        x, y, yyyy= batch

        # Noise
        x += self.User_NoiseX *  torch.randn(x.shape, device = self.device_)# NOTE Noise added in training
        logits = self.forward(x)

        p = F.softmax(logits,-1)

        #loss = self.loss(logits, yyyy)
        loss = self.loss(logits, yyyy)

        if self.User_AddL1 > 0.0:
            l1_reg = torch.tensor(0.0, device = self.device_)
            for _ , t in enumerate(self.parameters()):
                    l1_reg += torch.mean(torch.flatten(t).abs())
            loss += self.User_AddL1 * l1_reg

        # Visualisation scores
        if self.User_Mixup:
            y = torch.argmax(y, dim=1)

        #y_hot = torch.nn.functional.one_hot(y.type(torch.int64), num_classes=self.n_class)

        ACC = torchmetrics.functional.accuracy(p, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        PR = torchmetrics.functional.precision_recall(p, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        ACC2 = torchmetrics.functional.accuracy(p, y, top_k =2, average = 'weighted', num_classes = self.n_class)
        PR2 = torchmetrics.functional.precision_recall(p, y, top_k =2, average = 'weighted', num_classes = self.n_class)

        ACC_mi = torchmetrics.functional.accuracy(p, y, top_k =1, average = 'micro', num_classes = self.n_class)
        #PR_mi = torchmetrics.functional.precision_recall(p, y, top_k =1, average = 'micro', num_classes = self.n_class)
        ACC_ma = torchmetrics.functional.accuracy(p, y, top_k =1, average = 'macro', num_classes = self.n_class)
        #PR_ma = torchmetrics.functional.precision_recall(p, y, top_k =1, average = 'macro', num_classes = self.n_class)

        ACC2_mi = torchmetrics.functional.accuracy(p, y, top_k =2, average = 'micro', num_classes = self.n_class)
        #PR2_mi = torchmetrics.functional.precision_recall(p, y, top_k =2, average = 'micro', num_classes = self.n_class)
        ACC2_ma = torchmetrics.functional.accuracy(p, y, top_k =2, average = 'macro', num_classes = self.n_class)
        #PR2_ma = torchmetrics.functional.precision_recall(p, y, top_k =2, average = 'macro', num_classes = self.n_class)

        SF = self.CatalogueLoss["SigmoidalFocalLoss"]
        SM = self.CatalogueLoss["MultiLabelSoftMarginLoss"]
        self.log('train_softmargin',SM(p,yyyy) )
        self.log('train_sigmoidalfocal',SF(p,yyyy) )
        self.log('train_precision', PR[0])
        self.log('train_recall', PR[1])
        self.log('train_acc', ACC)
        self.log('train_precision2', PR2[0])
        self.log('train_recall2', PR2[1])
        self.log('train_acc2', ACC2)

        self.log('train_acc_mi', ACC_mi)
        #self.log('train_recall_mi', PR_mi[1])
        #self.log('train_precision_mi', PR_mi[0])
        self.log('train_acc2_mi', ACC2_mi)
        #self.log('train_recall2_mi', PR2_mi[1])
        #self.log('train_precision2_mi', PR2_mi[0])

        self.log('train_acc_ma', ACC_ma)
        #self.log('train_recall_ma', PR_ma[1])
        #self.log('train_precision_ma', PR_ma[0])
        self.log('train_acc2_ma', ACC2_ma)
        #self.log('train_recall2_ma', PR2_ma[1])
        #self.log('train_precision2_ma', PR2_ma[0])

        self.log('train_loss_s', loss, prog_bar=True)
        return loss

    def validation_step(self, batch, batch_idx):
        x, y, yyyy = batch
        logits = self.forward(x)
        p = F.softmax(logits,-1)
        #CE = nn.CrossEntropyLoss()
        #loss = CE(logits, y) #self.loss(logits, y) # NOTE Validate without the random
        #loss_functional = nn.CrossEntropyLoss(label_smoothing=0.0)#self.User_LabelSmoothing)
        #loss = loss_functional(logits, y)
        loss = self.loss(logits, yyyy)

        #y_hot = torch.nn.functional.one_hot(y.type(torch.int64), num_classes=self.n_class)

        if self.User_Mixup:
            pass # NOTE Because mixup is not called in validation_start hook
        SF = self.CatalogueLoss["SigmoidalFocalLoss"]
        SM = self.CatalogueLoss["MultiLabelSoftMarginLoss"]
        self.log('val_softmargin',SM(p,yyyy) )
        self.log('val_sigmoidalfocal',SF(p,yyyy) )

        # NOTE I will just monitor L1
        l1_reg = torch.tensor(0.0, device = self.device_)
        for _ , t in enumerate(self.parameters()):
                l1_reg += torch.mean(torch.flatten(t).abs())

        self.log("L1", l1_reg)
        self.log('val_loss_s', loss, prog_bar=True)
        self.log("val_loss", loss)
        #print(p,y)
        ACC = torchmetrics.functional.accuracy(p, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        PR = torchmetrics.functional.precision_recall(p, y, top_k =1, average = 'weighted', num_classes = self.n_class)
        ACC2 = torchmetrics.functional.accuracy(p, y, top_k =2, average = 'weighted', num_classes = self.n_class)
        PR2 = torchmetrics.functional.precision_recall(p, y, top_k =2, average = 'weighted', num_classes = self.n_class)

        ACC_mi = torchmetrics.functional.accuracy(p, y, top_k =1, average = 'micro', num_classes = self.n_class)
        #PR_mi = torchmetrics.functional.precision_recall(p, y, top_k =1, average = 'micro', num_classes = self.n_class)
        ACC_ma = torchmetrics.functional.accuracy(p, y, top_k =1, average = 'macro', num_classes = self.n_class)
        #PR_ma = torchmetrics.functional.precision_recall(p, y, top_k =1, average = 'macro', num_classes = self.n_class)

        ACC2_mi = torchmetrics.functional.accuracy(p, y, top_k =2, average = 'micro', num_classes = self.n_class)
        #PR2_mi = torchmetrics.functional.precision_recall(p, y, top_k =2, average = 'micro', num_classes = self.n_class)
        ACC2_ma = torchmetrics.functional.accuracy(p, y, top_k =2, average = 'macro', num_classes = self.n_class)
        #PR2_ma = torchmetrics.functional.precision_recall(p, y, top_k =2, average = 'macro', num_classes = self.n_class)

        self.log('val_acc', ACC)
        self.log('val_recall', PR[1])
        self.log('val_precision', PR[0])
        self.log('val_acc2', ACC2)
        self.log('val_recall2', PR2[1])
        self.log('val_precision2', PR2[0])

        self.log('val_acc_mi', ACC_mi)
        #self.log('val_recall_mi', PR_mi[1])
        #self.log('val_precision_mi', PR_mi[0])
        self.log('val_acc2_mi', ACC2_mi)
        #self.log('val_recall2_mi', PR2_mi[1])
        #self.log('val_precision2_mi', PR2_mi[0])

        self.log('val_acc_ma', ACC_ma)
        #self.log('val_recall_ma', PR_ma[1])
        #self.log('val_precision_ma', PR_ma[0])
        self.log('val_acc2_ma', ACC2_ma)
        #self.log('val_recall2_ma', PR2_ma[1])
        #self.log('val_precision2_ma', PR2_ma[0])

        self.log("hp_metric", ACC)

        return loss

    def predict_step(self, batch, batch_idx):
        x, y = batch
        logits = self.forward(x)
        p = torch.softmax(logits, dim=1)
        return p

    def predict_p(self, batch):
        x = batch
        logits = self.forward(x)
        p = torch.softmax(logits, dim=1)
        return p

    def configure_optimizers(self):
        optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay = self.User_AdamW_weight_decay)
        #optimizer = torch.optim.SGD(self.parameters(), lr=self.learning_rate, momentum=0.9,
        #                            weight_decay=0.01, nesterov=True)
        #optimizer = torch.optim.Adadelta(self.parameters(), lr=self.learning_rate, rho=0.9, eps=1e-06, weight_decay=0.001)

        lr_scheduler_ReduceLrEveryEpoch = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,
                                patience=1, factor=0.1, mode='min',
                                verbose=True,
                                threshold_mode='rel',
                                threshold = 0.01, # NOTE In rel mode, dynamic_threshold = best * ( 1 + threshold ) in ‘max’ mode or best * ( 1 - threshold ) in min mode.
                                min_lr= self.User_min_lr, cooldown = self.User_CooldownInterval)

        if self.User_LrScheduler == 'CosineAnnealingLR':
            lr_scheduler =  torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max = self.User_CooldownInterval,
                                                                        eta_min=self.User_min_lr,
                                                                        last_epoch=-1, verbose=False)
        if self.User_LrScheduler == 'CosineAnnealingWarmRestarts':
            lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, self.User_CooldownInterval, T_mult=1,
                                                                        eta_min=self.User_min_lr,
                                                                        last_epoch=-1, verbose=False)
        if self.User_LrScheduler == 'DescendingCosineAnnealingLR_HalfEpoch':
            lr_scheduler = NucleicNet.Burn.LRS.DescendingCosineAnnealingLR_HalfEpoch(optimizer, T_max = self.User_CooldownInterval,
                                                                        eta_min=self.User_min_lr,
                                                                        last_epoch=-1, verbose=False,
                                                                        n_step_per_epoch = 500000,
                                                                        User_ShiftLrRatio = self.User_ShiftLrRatio,
                                                                        final_eta_min = 1e-10)
        if self.User_LrScheduler == 'SimpleMultistepCosineLRS':
            lr_scheduler = NucleicNet.Burn.LRS.SimpleMultistepCosineLRS(optimizer, last_epoch=-1, verbose=False,
                                                                        jumpeverystep = 20000,
                                                                        T_max = self.User_CooldownInterval,
                                                                        jumpfactor = 0.5, eta_min=self.User_min_lr,
                                                                        AssignSteps = [10000, 160000]
                                                                        )
        if self.User_LrScheduler == 'SimpleMultistepCosineLRS_SXPR':
            lr_scheduler = NucleicNet.Burn.LRS.SimpleMultistepCosineLRS(optimizer, last_epoch=-1, verbose=False,
                                                                        jumpeverystep = 20000,
                                                                        T_max = self.User_CooldownInterval,
                                                                        jumpfactor = 0.5, eta_min=self.User_min_lr,
                                                                        AssignSteps = [10000, 160000]
                                                                        )
        if self.User_LrScheduler == 'MultistepCosineAnnealingLRS':
            lr_scheduler = NucleicNet.Burn.LRS.MultistepCosineAnnealingLRS(optimizer, last_epoch=-1, verbose=False,
                                                                        jumpeverystep = 20000,
                                                                        T_max = self.User_CooldownInterval,
                                                                        jumpfactor = 0.5, eta_min=self.User_min_lr,
                                                                        AssignSteps = [10000] #[40000, 80000, 160000]
                                                                        )

        return (
                    {
                        "optimizer": optimizer,
                        "lr_scheduler": {
                            "scheduler": lr_scheduler,
                            'reduce_on_plateau': True,
                            "interval": "step",
                            "frequency": 1,
                            "monitor": "train_loss_s",
                        # If "monitor" references validation metrics, then "frequency" should be set to a
                        # multiple of "trainer.check_val_every_n_epoch".
                        },
                    },

        )

    def _init_params(self):

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity=Catalogue_Activation[self.User_Activation])
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)

# We should try to move the inverse-vec here. possibly also some eigvec here after B1hw we can use einsum
# TODO TODO BVec_FcLogits(pl.LightningModule)

# =================================
# Resnet
# =================================
from torch import jit
# NOTE These are customised to take radial shell inputs. with B1hw (h is the shell, w is the feature)
class B1hw_BlockPreActResnet(jit.ScriptModule):
    def __init__(self,
                    n_FeatPerShell = 80,
                    n_Shell = 6,
                    n_ShellMix = 2,
                    act_fn = Catalogue_Activation['gelu'],
                    blockposition = 0,
                    User_NoiseZ = None,
                    device = torch.device('cuda'),
                    ):
        super().__init__()
        self.User_NoiseZ = User_NoiseZ
        self.blockposition = blockposition
        self.device_ = device
        if help:
            """
            # NOTE For some 1-D tensor f = (b,1,h*w) vectorized from some F = (b,1,h,w)
            #      f = Vec(F) NOTE This is done in T1.BVec_B1hw
            #      The input here is some F = (b,1,h,w)
            #      where f was structured by shell index h; index w is the feature index within a shell.
            #      The output is a Resnet block with color channel batch normalised correctly
            #      https://arxiv.org/abs/1603.05027
            #      TODO Downsample maybe implemented by recursion and stride.
            """
        #print('bpreact, n_feat',n_FeatPerShell)
        self.net = nn.Sequential(
            # NOTE Batch normalisation done right woth Preactivation
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),
        )
        self.net2a = nn.Sequential(
            #nn.BatchNorm2d(num_features = n_FeatPerShell),
            NucleicNet.Burn.T1.GhostBatchNorm2D(num_features= n_FeatPerShell, virtual_batch_size=128, eps=1e-05, momentum=0.1, affine=True),
        )
        self.net2b= nn.Sequential(
            act_fn(),
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),
        )
        self.net3 = nn.Sequential(
            # NOTE Convolve along shell extracting useful combination of features in adjacent shells
            NucleicNet.Burn.T1.B1hw_ShellConv(n_FeatPerShell = n_FeatPerShell, n_Shell = n_Shell, n_ShellMix = n_ShellMix),

            # NOTE  Batch normalisation done right woth Preactivation
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),
            #nn.BatchNorm2d(num_features = n_FeatPerShell),
            NucleicNet.Burn.T1.GhostBatchNorm2D(num_features= n_FeatPerShell, virtual_batch_size=128, eps=1e-05, momentum=0.1, affine=True),
            act_fn(),
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),

            #nn.AdaptiveMaxPool2d((int(n_Shell/2), int(n_FeatPerShell/2))),
            #torch.nn.ConvTranspose2d(1, 1, 2, stride=2, padding=0,
            #                        output_padding=0, groups=1, bias=False, dilation=1,
            #                        padding_mode='zeros', device=None, dtype=None),

            # NOTE Convolve along shell extracting useful combination of features in adjacent shells
            NucleicNet.Burn.T1.B1hw_ShellConv(n_FeatPerShell = n_FeatPerShell,n_Shell = n_Shell, n_ShellMix = n_ShellMix),
        )

    @jit.script_method
    def forward(self, x):

        z = self.net(x)
        z = self.net2a(z)
        if (self.blockposition <= 2) & (self.training) & (self.User_NoiseZ > 0.0):
            z += self.User_NoiseZ *  torch.randn(z.shape, device = self.device_)
        z = self.net2b(z)
        z = self.net3(z)
        out = z + x
        return out

#class B1hw_BlockBottleneckResnet(nn.Module):
class B1hw_BlockBottleneckResnet(jit.ScriptModule):
    def __init__(self,
                    n_FeatPerShell = 80,
                    n_channelbottleneck = 40,
                    n_Shell = 6,
                    n_ShellMix = 2,
                    act_fn = Catalogue_Activation['gelu'],
                    device = torch.device('cuda'),
                    blockposition = 0,
                    User_NoiseZ = None,
                    ):
        super().__init__()

        if help:
            """
            # NOTE For some 1-D tensor f = (b,1,h*w) vectorized from some F = (b,1,h,w)
            #      f = Vec(F) NOTE This is done in T1.BVec_B1hw
            #      The input here is some F = (b,1,h,w)
            #      where f was structured by shell index h; index w is the feature index within a shell.
            #      The output is a Resnet block with color channel batch normalised correctly
            #      https://arxiv.org/abs/1603.05027
            #      TODO Downsample maybe implemented by recursion and stride.
            # Bottleneck in torchvision places the stride for downsampling at 3x3 convolution(self.conv2)
            # while original implementation places the stride at the first 1x1 convolution(self.conv1)
            # according to "Deep residual learning for image recognition"https://arxiv.org/abs/1512.03385.
            # This variant is also known as ResNet V1.5 and improves accuracy according to
            # https://ngc.nvidia.com/catalog/model-scripts/nvidia:resnet_50_v1_5_for_pytorch.
            """
        self.n_Shell = n_Shell
        self.selectshell = torch.arange(self.n_Shell, device= device)
        self.act_fn = act_fn()
        self.net1 = nn.Sequential(
            # NOTE Batch normalisation done right woth Preactivation
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),
            nn.Conv2d(n_FeatPerShell, n_channelbottleneck, kernel_size=1, stride=1, bias=False),
            #nn.BatchNorm2d(num_features = n_channelbottleneck),
            NucleicNet.Burn.T1.GhostBatchNorm2D(num_features= n_channelbottleneck, virtual_batch_size=128, eps=1e-05, momentum=0.1, affine=True),
        )
        self.net2a = nn.Sequential(
            act_fn(),
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),

            #nn.AdaptiveMaxPool2d((int(n_Shell/2), int(n_channelbottleneck/2))),
            #torch.nn.ConvTranspose2d(1, 1, 2, stride=2, padding=0,
            #                        output_padding=0, groups=1, bias=False, dilation=1,
            #                        padding_mode='zeros', device=None, dtype=None),

        )
        self.widedrop = nn.Dropout(p=0.1, inplace=False)
        self.net2b = nn.Sequential(

            # NOTE Convolve along shell extracting useful combination of features in adjacent shells
            NucleicNet.Burn.T1.B1hw_ShellConv(n_FeatPerShell = n_channelbottleneck, n_Shell = n_Shell, n_ShellMix = n_ShellMix),

            # NOTE  Batch normalisation done right woth Preactivation
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),
            #nn.BatchNorm2d(num_features = n_channelbottleneck),
            NucleicNet.Burn.T1.GhostBatchNorm2D(num_features= n_channelbottleneck, virtual_batch_size=128, eps=1e-05, momentum=0.1, affine=True),
            act_fn(),
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),

            # NOTE Convolve along shell extracting useful combination of features in adjacent shells
            #NucleicNet.Burn.T1.B1hw_ShellConv(n_FeatPerShell = n_FeatPerShell,n_Shell = n_Shell, n_ShellMix = n_ShellMix),
            nn.Conv2d(in_channels = 1, out_channels = n_FeatPerShell,
                        kernel_size = (n_ShellMix,n_channelbottleneck),
                        padding=(n_ShellMix - 1 ,0),
                        stride=1, dilation=1, groups=1,
                        bias=False, padding_mode='zeros'),
                        #device=None, dtype=None),
            NucleicNet.Burn.T1.Bnhw_Permute(dimorder=(0,3,2,1)),

        )
        self.blockposition = blockposition
        self.device_ = device
        assert (User_NoiseZ is not None), 'ABORTED. B1hw_BlockBottleneckResnet User_NoiseZ is None'

        self.User_NoiseZ = User_NoiseZ

    @jit.script_method
    def forward(self, x):

        z = self.net1(x)

        if (self.blockposition <= 2) & (self.training) & (self.User_NoiseZ > 0.0):
            z += self.User_NoiseZ *  torch.randn(z.shape, device = self.device_)
        z = self.net2a(z)
        #if (self.blockposition <= 2):
        #    z=self.widedrop(z)
        # NOTE Worsen if drop here.
        z = self.net2b(z)
        #print(z.shape)
        z = z.index_select(2, self.selectshell)
        out = z + x
        out = self.act_fn(out)
        return out

Catalogue_BlockResnet = {"B1hw_BlockPreActResnet" : B1hw_BlockPreActResnet,
                        "B1hw_BlockBottleneckResnet" : B1hw_BlockBottleneckResnet}

# NOTE Resnet
#class B1hw_LayerResnet(nn.Module):
class B1hw_LayerResnet(jit.ScriptModule):
    def __init__(self,
                    n_FeatPerShell = 80,
                    n_Shell = 6,
                    n_ShellMix = 2,
                    User_Activation = 'gelu',
                    User_Block = "B1hw_BlockPreActResnet",
                    n_Blocks = 16,
                    #ShellIPCA = None,
                    ManualInitiation = False,
                    device = torch.device('cuda')):
        super(B1hw_LayerResnet, self).__init__()

        if help:
            """
            # NOTE For some 1-D tensor f = (b,1,h*w) vectorized from some F = (b,1,h,w)
            #      f = Vec(F) NOTE This is done in T1.BVec_B1hw
            #      The input here is some F = (b,1,h,w)
            #      where f was structured by shell index h; index w is the feature index within a shell.
            #      The output is a series of Resnet block
            #      TODO Downsample maybe implemented by recursion and stride.
            """

        self.n_Blocks = n_Blocks
        self.User_Activation = User_Activation
        self.User_Block = User_Block

        self.n_FeatPerShell = n_FeatPerShell
        self.n_Shell = n_Shell
        self.n_ShellMix = n_ShellMix

        self._create_network()
        if ManualInitiation:
            self._init_params()
        #self.save_hyperparameters()

    def _create_network(self):
      blocks = []
      for _ in range(self.n_Blocks):
            current_Block_Functional = Catalogue_BlockResnet[self.User_Block]
            current_Activation_Functional = Catalogue_Activation[self.User_Activation]
            blocks.append(
                current_Block_Functional(
                    n_FeatPerShell = self.n_FeatPerShell,
                    n_Shell = self.n_Shell,
                    n_ShellMix = self.n_ShellMix,
                    act_fn = current_Activation_Functional)
                # TODO With bottleneck layer
                    )

      self.blocks = nn.Sequential(*blocks)

    def _init_params(self):

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity=Catalogue_Activation[self.HparamDict["Activation"]])
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
    @jit.script_method
    def forward(self, x):

        x = self.blocks(x)
        return x

#class B1hw_LayerResnetBottleneck(nn.Module):
class B1hw_LayerResnetBottleneck(jit.ScriptModule):
    def __init__(self,
                    n_FeatPerShell = 80,
                    n_Shell = 6,
                    n_ShellMix = 2,
                    User_Activation = 'gelu',
                    User_n_channelbottleneck = 40,
                    User_Block = "B1hw_BlockPreActResnet",
                    n_Blocks = 16,
                    User_NoiseZ = 0.01,
                    #ShellIPCA = None,
                    ManualInitiation = False,
                    device = torch.device('cuda')):
        super(B1hw_LayerResnetBottleneck, self).__init__()

        if help:
            """
            # NOTE For some 1-D tensor f = (b,1,h*w) vectorized from some F = (b,1,h,w)
            #      f = Vec(F) NOTE This is done in T1.BVec_B1hw
            #      The input here is some F = (b,1,h,w)
            #      where f was structured by shell index h; index w is the feature index within a shell.
            #      The output is a series of Resnet block
            #      TODO Downsample maybe implemented by recursion and stride.
            """

        self.n_Blocks = n_Blocks
        self.User_Activation = User_Activation
        self.User_Block = User_Block
        self.User_NoiseZ = User_NoiseZ
        self.n_FeatPerShell = n_FeatPerShell
        self.n_Shell = n_Shell
        self.n_ShellMix = n_ShellMix
        self.n_channelbottleneck = User_n_channelbottleneck

        self._create_network()
        if ManualInitiation:
            self._init_params()
        #self.save_hyperparameters()

    def _create_network(self):
      blocks = []
      for _ in range(int(self.n_Blocks/2)):
            current_Block_Functional = Catalogue_BlockResnet[self.User_Block]
            current_Block_Bottleneck = Catalogue_BlockResnet["B1hw_BlockBottleneckResnet"]
            current_Activation_Functional = Catalogue_Activation[self.User_Activation]
            blocks.append(
                current_Block_Functional(
                    n_FeatPerShell = self.n_FeatPerShell,
                    n_Shell = self.n_Shell,
                    n_ShellMix = self.n_ShellMix,
                    act_fn = current_Activation_Functional,
                    blockposition = _ ,
                    User_NoiseZ = self.User_NoiseZ
                    )
                    )
            blocks.append(
                current_Block_Bottleneck(
                    n_FeatPerShell = self.n_FeatPerShell,
                    n_channelbottleneck = self.n_channelbottleneck,
                    n_Shell = self.n_Shell,
                    n_ShellMix = self.n_ShellMix,
                    act_fn = current_Activation_Functional,
                    blockposition = _ ,
                    User_NoiseZ = self.User_NoiseZ)

                    )

      self.blocks = nn.Sequential(*blocks)

    def _init_params(self):

        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight, mode="fan_out", nonlinearity=Catalogue_Activation[self.HparamDict["Activation"]])
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
    @jit.script_method
    def forward(self, x):

        x = self.blocks(x)
        #x = self.normlayer(x) # NOTE This is NOT a good idea. batch normalising the last layer will hurt performance
        return x
# =========================
# Legacy B1hw_FcLogits Config for optimizer
# =========================

def LEGACY_configure_optimizers(self):
        optimizer = torch.optim.AdamW(self.parameters(), lr=self.learning_rate, weight_decay = self.User_AdamW_weight_decay)
        #optimizer = torch.optim.SGD(self.parameters(), lr=self.learning_rate, momentum=0.9)
        #optimizer = torch.optim.Adadelta(self.parameters(), lr=self.learning_rate, rho=0.9, eps=1e-06, weight_decay=0.001)
        if self.User_LrScheduler == 'ReduceLROnPlateau':
            lr_scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=100, factor=0.951,
                                verbose=False,
                                # NOTE This threshold is the "within epsilon" for the loss to be counted as unchanged
                                # should be around 1e-4 to 5
                                # it alsoimplies the lowest minima acheivable,
                                threshold = 5e-5,
                                min_lr= self.User_min_lr, cooldown = self.User_CooldownInterval)
        if self.User_LrScheduler == 'CosineAnnealingLR':
            lr_scheduler =  torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max = self.User_CooldownInterval,
                                                                        eta_min=self.User_min_lr,
                                                                        last_epoch=-1, verbose=False)
        if self.User_LrScheduler == 'CosineAnnealingWarmRestarts':
            lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, self.User_CooldownInterval, T_mult=1,
                                                                        eta_min=self.User_min_lr,
                                                                        last_epoch=-1, verbose=False)
        return {
                "optimizer": optimizer,
                "lr_scheduler": {
                    "scheduler": lr_scheduler,
                    'reduce_on_plateau': True,
                    "interval": "step",
                    "frequency": 1,
                    "monitor": "train_loss_s",
                # If "monitor" references validation metrics, then "frequency" should be set to a
                # multiple of "trainer.check_val_every_n_epoch".
            },
        }

# =================================================================================
#    NucleicNet
#    Copyright (C) 2019-2022  Jordy Homing Lam, JHML. All rights reserved.
#
#    Acknowledgement.
#    JHML would like to thank Mingyi Xue and Joshua Chou for their patience and efforts
#    in the debugging process and Prof. Xin Gao and Prof. Xuhui Huang for their
#    continuous support.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Redistribution and use in source and binary forms, with or without
#    modification, are permitted provided that the following conditions are
#    met:
#
#    * Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation and/or
#    other materials provided with the distribution.
#    * Cite our work at Lam, J.H., Li, Y., Zhu, L. et al. A deep learning framework to predict binding preference of RNA constituents on protein surface. Nat Commun 10, 4941 (2019). https://doi.org/10.1038/s41467-019-12920-0
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.
# ==================================================================================


#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import unicode_literals

AUTHOR = 'Bharadwaj Machiraju'
SITENAME = 'bharadwaj.machiraju'
SITEURL = 'https://tunnelshade.in'

PATH = 'content'

TIMEZONE = 'Asia/Kolkata'
DEFAULT_DATE_FORMAT = "%d-%m-%y"

DEFAULT_LANG = 'en'

# Feed generation is usually not desired when developing
FEED_ALL_ATOM = 'feeds/all.atom.xml'
CATEGORY_FEED_ATOM = None
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None

# Blogroll
LINKS = (('Pelican', 'http://getpelican.com/'),
         ('You can modify those links in your config file', '#'),)

# Social widget
SOCIAL = ((' @tunnelshade_', 'https://twitter.com/tunnelshade_'),
          (' Github', 'https://github.com/tunnelshade'),
          (' LinkedIn', 'https://www.linkedin.com/in/tunnelshade/'),
          (' domain_without_tld@gmail.com', 'domain_without_tld@gmail.com'),)

DEFAULT_PAGINATION = 5
PAGINATION_PATTERNS = (
        (1, '{base_name}/', '{base_name}/index.html'),
        (2, '{base_name}/page/{number}/', '{base_name}/page/{number}/index.html'),)

# Uncomment following line if you want document-relative URLs when developing
THEME = 'hackish'
RELATIVE_URLS = True

# Dont' display categories on Menu
DISPLAY_CATEGORIES_ON_MENU = False
DISPLAY_PAGES_ON_MENU = False

ARTICLE_PATHS = ['blog']
ARTICLE_URL = 'blog/{date:%Y}/{date:%m}/{slug}/'
ARTICLE_SAVE_AS = 'blog/{date:%Y}/{date:%m}/{slug}/index.html'
INDEX_SAVE_AS = 'blog/index.html'

PAGE_PATHS = ['pages']
PAGE_URL = '{slug}/'
PAGE_SAVE_AS = '{slug}/index.html'

TAG_URL = 'tag/{slug}/'
TAG_SAVE_AS = 'tag/{slug}/index.html'
TAGS_URL = 'tags/'
TAGS_SAVE_AS = 'tags/index.html'

AUTHOR_URL = 'author/{slug}/'
AUTHOR_SAVE_AS = 'author/{slug}/index.html'
AUTHORS_URL = 'authors/'
AUTHORS_SAVE_AS = 'authors/index.html'

CATEGORY_URL = 'category/{slug}/'
CATEGORY_SAVE_AS = 'category/{slug}/index.html'
CATEGORYS_URL = 'categories/'
CATEGORYS_SAVE_AS = 'categories/index.html'

STATIC_PATHS = ['images']

GANALYTICS_DOMAIN = None
GANALYTICS_TRACKING_ID = None

DISQUS_SITENAME = None