from rdkit import Chem

import numpy as np
from graph_features import atom_features,one_of_k_encoding_unk

class Featurizer(object):

  def featurize(self, mols, verbose=True, log_every_n=1000):
    mols = list(mols)
    features = []
    for i, mol in enumerate(mols):
      if mol is not None:
        features.append(self._featurize(mol))
      else:
        features.append(np.array([]))

    features = np.asarray(features)
    return features

  def _featurize(self, mol):
    raise NotImplementedError('Featurizer is not defined.')

  def __call__(self, mols):
    return self.featurize(mols)

def get_atom_type(atom):
  elem = atom.GetAtomicNum()
  hyb = str(atom.GetHybridization).lower()
  if elem == 1:
    return (0)
  if elem == 4:
    return (1)
  if elem == 5:
    return (2)
  if elem == 6:
    if "sp2" in hyb:
      return (3)
    elif "sp3" in hyb:
      return (4)
    else:
      return (5)
  if elem == 7:
    if "sp2" in hyb:
      return (6)
    elif "sp3" in hyb:
      return (7)
    else:
      return (8)
  if elem == 8:
    if "sp2" in hyb:
      return (9)
    elif "sp3" in hyb:
      return (10)
    else:
      return (11)
  if elem == 9:
    return (12)
  if elem == 15:
    if "sp2" in hyb:
      return (13)
    elif "sp3" in hyb:
      return (14)
    else:
      return (15)
  if elem == 16:
    if "sp2" in hyb:
      return (16)
    elif "sp3" in hyb:
      return (17)
    else:
      return (18)
  if elem == 17:
    return (19)
  if elem == 35:
    return (20)
  if elem == 53:
    return (21)
  return (22)

def get_atom_adj_matrices(mol,
                          n_atom_types,
                          max_n_atoms=150,
                          max_valence=6,
                          K = 1,
                          L = 1,
                          graph_conv_features=True,
                          EGCNN_flag = False,
                          nxn=True):
  if not graph_conv_features:
    bond_matrix = np.zeros((max_n_atoms, 4 * max_valence)).astype(np.uint8)
  if EGCNN_flag:
    EGCNN_A = np.zeros((max_n_atoms, K, max_n_atoms)).astype(np.uint8)
    EGCNN_H = np.zeros((max_n_atoms, max_n_atoms, L)).astype(np.uint8)
    for b in mol.GetBonds():
      t = b.GetBondType()
      k = 0
      if (K != 1):
        if t == Chem.rdchem.BondType.SINGLE:
          k = 0
        elif t == Chem.rdchem.BondType.DOUBLE:
          k = 1
        elif t == Chem.rdchem.BondType.TRIPLE:
          k = 2
        elif t == Chem.rdchem.BondType.AROMATIC:
          k = 3
        else:
          k= 3
      EGCNN_A[b.GetEndAtomIdx(),k ,b.GetBeginAtomIdx()] = 1
      EGCNN_A[b.GetBeginAtomIdx(), k, b.GetEndAtomIdx()] = 1
      source_atom = mol.GetAtomWithIdx(b.GetBeginAtomIdx())
      target_atom = mol.GetAtomWithIdx(b.GetEndAtomIdx())
      source_atom_valence = source_atom.GetImplicitValence()
      target_atom_valence = target_atom.GetImplicitValence()
      edge_vector = one_of_k_encoding_unk(source_atom.GetImplicitValence(), [0, 1, 2, 3, 4, 5, 6])+one_of_k_encoding_unk(target_atom.GetImplicitValence(), [0, 1, 2, 3, 4, 5, 6])
      edge_vector = np.array(edge_vector,dtype=np.int32)
      if (L != 1):
        # l_edge_vector_bin = list(bin(source_atom_valence)[2:])
        # r_edge_vector_bin = list(bin(target_atom_valence)[2:])
        # for i in range(L//2):
        #   if i<len(l_edge_vector_bin):
        #     edge_vector[i+L//2] = l_edge_vector_bin[i]
        # for i in range(L//2):
        #   if i<len(r_edge_vector_bin):
        #     edge_vector[i] = r_edge_vector_bin[i]
        EGCNN_H[b.GetBeginAtomIdx(), b.GetEndAtomIdx(), :] = edge_vector
        EGCNN_H[b.GetEndAtomIdx(), b.GetBeginAtomIdx(), :] = edge_vector
      else:
        EGCNN_H[b.GetBeginAtomIdx(), b.GetEndAtomIdx(), :] = 1
        EGCNN_H[b.GetEndAtomIdx(), b.GetBeginAtomIdx(), :] = 1
    EGCNN_R = np.zeros((max_n_atoms, max_n_atoms)).astype(np.uint8)
    for a_idx in range(0, mol.GetNumAtoms()):
      atom = mol.GetAtomWithIdx(a_idx)
      neighbor_num = len(atom.GetNeighbors())
      for n_idx, neighbor in enumerate(atom.GetNeighbors()):
        EGCNN_R[a_idx, neighbor.GetIdx()] = 1.0 / neighbor_num
      EGCNN_R[a_idx,a_idx] = 1.0
  if nxn:
    adj_matrix = np.zeros((max_n_atoms, max_n_atoms)).astype(np.uint8)
  else:
    adj_matrix = np.zeros((max_n_atoms, max_valence)).astype(np.uint8)
    adj_matrix += (adj_matrix.shape[0] - 1)

  if not graph_conv_features:
    atom_matrix = np.zeros((max_n_atoms, n_atom_types + 3)).astype(np.uint8)
    atom_matrix[:, atom_matrix.shape[1] - 1] = 1

  atom_arrays = []
  for a_idx in range(0, mol.GetNumAtoms()):
    atom = mol.GetAtomWithIdx(a_idx)
    if graph_conv_features:
      atom_arrays.append(atom_features(atom))
      #atom_arrays.append(atom_features(atom))

    else:

      atom_type = get_atom_type(atom)
      atom_matrix[a_idx][-1] = 0
      atom_matrix[a_idx][atom_type] = 1

    for n_idx, neighbor in enumerate(atom.GetNeighbors()):
      if nxn:
        adj_matrix[a_idx][neighbor.GetIdx()] = 1
        adj_matrix[a_idx][a_idx] = 1
      else:
        adj_matrix[a_idx][n_idx] = neighbor.GetIdx()

      if not graph_conv_features:
        bond = mol.GetBondBetweenAtoms(a_idx, neighbor.GetIdx())
        bond_type = str(bond.GetBondType()).lower()
        if "single" in bond_type:
          bond_order = 0
        elif "double" in bond_type:
          bond_order = 1
        elif "triple" in bond_type:
          bond_order = 2
        elif "aromatic" in bond_type:
          bond_order = 3
        bond_matrix[a_idx][(4 * n_idx) + bond_order] = 1

  if graph_conv_features:
    n_feat = len(atom_arrays[0])
    atom_matrix = np.zeros((max_n_atoms, n_feat)).astype(np.uint8)
    for idx, atom_array in enumerate(atom_arrays):
      atom_matrix[idx, :] = atom_array
  else:
    atom_matrix = np.concatenate(
        [atom_matrix, bond_matrix], axis=1).astype(np.uint8)
  if EGCNN_flag:
    return (EGCNN_A.astype(np.uint8), atom_matrix.astype(np.uint8),EGCNN_H.astype(np.uint8),EGCNN_R.astype(np.uint8))
  else:
    return (adj_matrix.astype(np.uint8), atom_matrix.astype(np.uint8))

def featurize_mol(mol, n_atom_types, max_n_atoms, max_valence,
                  num_atoms_feature):
  adj_matrix, atom_matrix = get_atom_adj_matrices(mol, n_atom_types,
                                                  max_n_atoms, max_valence)
  if num_atoms_feature:
    return ((adj_matrix, atom_matrix, mol.GetNumAtoms()))
  return ((adj_matrix, atom_matrix))

def EGCNN_featurize_mol(mol,L,K,max_n_atoms):
  A,V,H,R = get_atom_adj_matrices(mol = mol,n_atom_types=23,max_n_atoms = max_n_atoms,K=K,L=L,EGCNN_flag=True)
  return (A,V,H,R,mol.GetNumAtoms())

class EGCNNFeaturizer(Featurizer):

  def __init__(self,
               max_n_atoms=150,
               K=1,
               L=1,
               ):
    self.max_n_atoms = max_n_atoms
    self.K = K
    self.L = L

  def featurize(self, rdkit_mols):
    cnt = 0
    for idx, mol in enumerate(rdkit_mols):
      if mol.GetNumAtoms() < self.max_n_atoms:
        cnt = cnt + 1
    featurized_mols = np.empty((cnt), dtype=object)
    # featurized_mols = np.empty((len(rdkit_mols)), dtype=object)
    for idx, mol in enumerate(rdkit_mols):
      if mol.GetNumAtoms() < self.max_n_atoms:
        featurized_mol = EGCNN_featurize_mol(mol, self.L, self.K, self.max_n_atoms)
        featurized_mols[idx] = featurized_mol
    return (featurized_mols)


import torch
import torch.nn as nn

class GaussianPolicy:

    def __init__(self, neural_mean, variance):

        self.variance = variance
        self.neural_net = neural_mean
        self.policy = None

    def distribution(self, observation):

        self.policy = torch.distributions.multivariate_normal.MultivariateNormal(self.neural_net(observation), covariance_matrix=self.variance)

    def sample(self):

        if self.policy == None:
            raise ValueError("Distribution not defined!")
        else:
            return self.policy.sample()

    def log_prob(self, observations, actions, batch_size):

        self.distribution(observations)

        return (1/batch_size)*self.policy.log_prob(actions)

class Neural_SoftMax:

    def __init__(self, neural_net, action_space):

        self.action_space = torch.tensor(action_space, dtype=torch.float32)
        self.neural_net = neural_net
        self.softmax = nn.Softmax(dim=1)
        self.policy = None

    def distribution(self, observations):

        features = self.neural_net(observations)
        self.policy = self.softmax(features)

    def sample(self):

        if self.policy == None:
            raise ValueError("Distribution not defined!")
        else:

            m = torch.distributions.Multinomial(1, self.policy)
            actions_idx = m.sample()
            actions = torch.zeros(actions_idx.shape[0], dtype=torch.int64)

            for ii, idx in enumerate(actions_idx):
                actions[ii] = (idx*self.action_space).sum()

            return actions

    def log_prob(self, observations, actions, batch_size):

        self.distribution(observations)
        actions_idx = torch.unsqueeze(actions, 1)

        return (1/batch_size)*torch.log(torch.gather(self.policy, 1, actions_idx))

class neuralnet(nn.Module):

    def __init__(self, input_size, output_size, hidden_layers, activation = nn.Tanh()):
        super(neuralnet, self).__init__()

        modules = []
        hidden_layers.insert(0, input_size)

        for ii, _ in enumerate(hidden_layers[:-1]):
            modules.append(nn.Linear(hidden_layers[ii], hidden_layers[ii+1]))
            modules.append(activation)

        modules.append(nn.Linear(hidden_layers[-1], output_size))

        self.sequential = nn.Sequential(*modules)

    def forward(self, x):
        return self.sequential(x)


from __future__ import print_function

"""
Calendar Server principal management web UI.
"""

__all__ = [
    "textAsEvent",
    "EventSourceResource",
]

from collections import deque

from zope.interface import implementer, Interface

from twistedcaldav.simpleresource import SimpleResource

from twisted.internet.defer import Deferred, succeed

from txweb2.stream import IByteStream, fallbackSplit
from txweb2.http_headers import MimeType
from txweb2.http import Response

def textAsEvent(text, eventID=None, eventClass=None, eventRetry=None):
    """
    Format some text as an HTML5 EventSource event.  Since the EventSource data
    format is text-oriented, this function expects L{unicode}, not L{bytes};
    binary data should be encoded as text if it is to be used in an EventSource
    stream.

    UTF-8 encoded L{bytes} are returned because
    http://www.w3.org/TR/eventsource/ states that the only allowed encoding
    for C{text/event-stream} is UTF-8.

    @param text: The text (ie. the message) to send in the event.
    @type text: L{unicode}

    @param eventID: An unique identifier for the event.
    @type eventID: L{unicode}

    @param eventClass: A class name (ie. a categorization) for the event.
    @type eventClass: L{unicode}

    @param eventRetry: The retry interval (in milliseconds) for the client to
        wait before reconnecting if it gets disconnected.
    @type eventRetry: L{int}

    @return: An HTML5 EventSource event as text.
    @rtype: UTF-8 encoded L{bytes}
    """
    if text is None:
        raise TypeError("text may not be None")

    event = []

    if eventID is not None:
        event.append(u"id: {0}".format(eventID))

    if eventClass is not None:
        event.append(u"event: {0}".format(eventClass))

    if eventRetry is not None:
        event.append(u"retry: {0:d}".format(eventRetry))

    event.extend(
        u"data: {0}".format(l) for l in text.split("\n")
    )

    return (u"\n".join(event) + u"\n\n").encode("utf-8")

class IEventDecoder(Interface):
    """
    An object that can be used to extract data from an application-specific
    event object for encoding into an EventSource data stream.
    """

    def idForEvent(event):
        """
        @return: An unique identifier for the given event.
        @rtype: L{unicode}
        """

    def classForEvent(event):
        """
        @return: A class name (ie. a categorization) for the event.
        @rtype: L{unicode}
        """

    def textForEvent(event):
        """
        @return: The text (ie. the message) to send in the event.
        @rtype: L{unicode}
        """

    def retryForEvent(event):
        """
        @return: The retry interval (in milliseconds) for the client to wait
            before reconnecting if it gets disconnected.
        @rtype: L{int}
        """

class EventSourceResource(SimpleResource):
    """
    Resource that vends HTML5 EventSource events.

    Events are stored in a ring buffer and streamed to clients.
    """

    addSlash = False

    def __init__(self, eventDecoder, principalCollections, bufferSize=400):
        """
        @param eventDecoder: An object that can be used to extract data from
            an event for encoding into an EventSource data stream.
        @type eventDecoder: L{IEventDecoder}

        @param bufferSize: The maximum number of events to keep in the ring
            buffer.
        @type bufferSize: L{int}
        """
        super(EventSourceResource, self).__init__(principalCollections, isdir=False)

        self._eventDecoder = eventDecoder
        self._events = deque(maxlen=bufferSize)
        self._streams = set()

    def addEvents(self, events):
        self._events.extend(events)

        # Notify outbound streams that there is new data to vend
        for stream in self._streams:
            stream.didAddEvents()

    def render(self, request):
        lastID = request.headers.getRawHeaders(u"last-event-id")

        response = Response()
        response.stream = EventStream(self._eventDecoder, self._events, lastID)
        response.headers.setHeader(
            b"content-type", MimeType.fromString(b"text/event-stream")
        )

        # Keep track of the event streams
        def cleanupFilter(_request, _response):
            self._streams.remove(response.stream)
            return _response

        # request.addResponseFilter(cleanupFilter)
        self._streams.add(response.stream)

        return response

@implementer(IByteStream)
class EventStream(object):
    """
    L{IByteStream} that streams out HTML5 EventSource events.
    """

    length = None

    def __init__(self, eventDecoder, events, lastID):
        """
        @param eventDecoder: An object that can be used to extract data from
            an event for encoding into an EventSource data stream.
        @type eventDecoder: L{IEventDecoder}

        @param events: Application-specific event objects.
        @type events: sequence of L{object}

        @param lastID: The identifier for the last event that was vended from
            C{events}.  Vending will resume starting from the following event.
        @type lastID: L{int}
        """
        super(EventStream, self).__init__()

        self._eventDecoder = eventDecoder
        self._events = events
        self._lastID = lastID
        self._closed = False
        self._deferredRead = None

    def didAddEvents(self):
        d = self._deferredRead
        if d is not None:
            self._deferredRead = None
            d.callback(None)

    def read(self):
        if self._closed:
            return succeed(None)

        lastID = self._lastID
        eventID = None

        idForEvent = self._eventDecoder.idForEvent
        classForEvent = self._eventDecoder.classForEvent
        textForEvent = self._eventDecoder.textForEvent
        retryForEvent = self._eventDecoder.retryForEvent

        for event in self._events:
            eventID = idForEvent(event)

            # If lastID is not None, skip messages up to and including the one
            # referenced by lastID.
            if lastID is not None:
                if eventID == lastID:
                    eventID = None
                    lastID = None

                continue

            eventClass = classForEvent(event)
            eventText = textForEvent(event)
            eventRetry = retryForEvent(event)

            self._lastID = eventID

            return succeed(
                textAsEvent(eventText, eventID, eventClass, eventRetry)
            )

        if eventID is not None:
            # We just scanned all the messages, and none are the last one the
            # client saw.
            self._lastID = None

            return succeed(b"")

        # # This causes the client to poll, which is undesirable, but the
        # # deferred below doesn't seem to work in real use...
        # return succeed(None)

        d = Deferred()
        self._deferredRead = d
        d.addCallback(lambda _: self.read())
        return d

    def split(self, point):
        return fallbackSplit(self, point)

    def close(self):
        self._closed = True


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()


import os
import requests
from dotenv import load_dotenv

from flask import Flask, render_template, redirect, url_for, request
from flask_bootstrap import Bootstrap
from flask_migrate import Migrate
from flask_wtf.csrf import CSRFProtect

from forms import EditMovieForm, AddMovieForm, ReviewMovieForm
from models import Movies, db

# load .env file & variables
load_dotenv()
MOVIEDB_API = os.environ["THEMOVIEDB_API_KEY"]
MOVIEDB_SEARCH_URL = "https://api.themoviedb.org/3/search/movie"
MOVIEDB_DETAILS_URL = "https://api.themoviedb.org/3/movie"
MOVIEDB_IMG_URL = "https://image.tmdb.org/t/p/w500/"

# make the flask app
app = Flask(__name__)
csrf = CSRFProtect(app)

app.config["SQLALCHEMY_DATABASE_URI"] = os.environ["DB_STRING"]
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]

# initialize the db with the app and add flask-bootstrap to the app
db.init_app(app)
Bootstrap(app)

# set to allow possible changes to the schema to be run with code
migrate = Migrate(app, db)

# use to create the db
with app.app_context():
    db.create_all()

# set up the various routes
#! the only thing at this moment that could be good to change is where the rank of the movies is set
#! the rank is set at the home route right now and while sorting the movies there seems to be good users may like to change a rank
#! right now there is no where to change the rank unless the rating is changed to be higher or lower than what is already in the db

@app.route("/")
def home():
    # pull the movie data from the db
    movie_list = db.session.execute(db.select(Movies).order_by(Movies.rating.desc())).scalars().all()
    # using the ordered list set the ranks for each movie in the list & commit
    for i in range(len(movie_list)):
        movie_list[i].ranking = i + 1
    db.session.commit()
    # pass to the template
    return render_template("index.html", movies=movie_list)

@app.route("/add", methods=["GET", "POST"])
def add():
    # initiate the add form
    add_form = AddMovieForm()
    # checks for the post method?
    # when form actually submitted
    if add_form.validate_on_submit():
        # taking the name of the movie from the form
        movie = add_form.title.data
        search_params = {
            "api_key": MOVIEDB_API,
            "query": movie
        }
        # API call to "https://www.themoviedb.org"
        movie_search_response = requests.get(MOVIEDB_SEARCH_URL, params=search_params)
        # JSON the results
        movie_data = movie_search_response.json()["results"]
        # post method pass to template
        return render_template("select.html", movies=movie_data)
    # initial passing of template to show for get method
    return render_template("add.html", form=add_form)

@app.route("/details", methods=["GET", "POST"])
def details():
    # initiate the review form
    review_form = ReviewMovieForm()
    # get the movie id from the search query address to pass for the API call
    movie_id = request.args.get("movie_id")
    search_params = {
        "api_key": MOVIEDB_API,
        "language": "en-US"
    }
    # API call to "https://www.themoviedb.org"
    movie_search_response = requests.get(f"{MOVIEDB_DETAILS_URL}/{movie_id}", params=search_params)
    # JSON the results
    movie_details = movie_search_response.json()
    if review_form.validate_on_submit():
        # adding the found movie to the database with the model
        movie = Movies(
            title=movie_details["title"],
            # this will take the release date and split to only show the year from the call results that are in "2023-04-15"
            year=movie_details["release_date"][0:4],
            description=movie_details["overview"],
            rating=review_form.rating.data,
            review=review_form.review.data,
            img_url=f"{MOVIEDB_IMG_URL}{movie_details['poster_path']}")
        # add the movie
        db.session.add(movie)
        # commit to the database so it saves
        db.session.commit()
        # redirect it back to the home page from the post method
        return redirect(url_for("home"))
    # get method template pull and passing information
    return render_template("review.html", form=review_form, movie=movie_details)

@app.route("/update", methods=["GET", "POST"])
def update():
    # initiate the edit form
    update_form = EditMovieForm()
    # get the movie id from the search query address to pass for the API call
    movie_id = request.args.get("movie_id")
    if update_form.validate_on_submit():
        # post method working
        # getting the specific movie clicked on from the db to update information
        movie_to_update = db.session.execute(db.select(Movies).filter_by(id=movie_id)).scalar_one()
        # update rating if the rating information was passed
        if update_form.update_rating.data:
            movie_to_update.rating = update_form.update_rating.data
        # update the review if the the review information was passed
        if update_form.review.data:
            movie_to_update.review = update_form.review.data
        # commit the changes
        db.session.commit()
        # redirect it to the home page
        return redirect(url_for("home"))
    # getting the specific movie from the click and query to pass to the edit template
    movie = db.session.execute(db.select(Movies).filter_by(id=movie_id)).scalar_one()
    return render_template("edit.html", form=update_form, movie=movie)

@app.route("/delete")
def delete():
    # getting the specific movie from the click and query to delete
    movie_id = request.args.get("movie_id")
    # find that specific movie in the db
    movie_to_delete = db.session.execute(db.select(Movies).filter_by(id=movie_id)).scalar_one()
    # delete that movie
    db.session.delete(movie_to_delete)
    # save the delete
    db.session.commit()
    # redirect tot he home page
    return redirect(url_for("home"))

# when the app's name is main run the app
if __name__ == "__main__":
    app.run()


import os
import torch
import numpy as np
from model import SegNet
from train import TRANSFER_LEARNING, IN_CHANNELS, NUM_CLASS, DEVICE
from matplotlib import pyplot as plt

def save_checkpoints(model, filename, epoch, optimizer, loss, train_acc, valid_acc):

    dirname = "/content/gdrive/MyDrive/Segmentation/check_points/large_aug"
    os.makedirs(dirname, exist_ok=True)

    save_path = os.path.join(dirname, filename)
    print(save_path)
    torch.save({
            'epoch': epoch,
            'model_state_dict': model.state_dict(),
            'optimizer_state_dict': optimizer.state_dict(),
            'loss': loss,
            'train_acc': train_acc,
            'valid_acc': valid_acc,
            'transfer_learning': TRANSFER_LEARNING
            }, save_path)

def load_checkpoints(filename, transfer_learning=True):

    dirname = "/content/gdrive/MyDrive/Segmentation/check_points/large_aug"
    file_path = os.path.join(dirname, filename)
    checkpoint = torch.load(file_path)
    if 'transfer_learning' in checkpoint:
        transfer_learning = checkpoint['transfer_learning']
    model = SegNet(IN_CHANNELS, NUM_CLASS, transfer_learning=transfer_learning)
    model.load_state_dict(checkpoint['model_state_dict'])

    print("Model Loaded: Epoch#{}\tLoss:{:.4f}\tTrainAcc:{:.4f}\tValidAcc:{:.4f}".format(
      checkpoint['epoch'],
      checkpoint['loss'],
      checkpoint['train_acc'],
      checkpoint['valid_acc'],
    ))
    return model.to(DEVICE)

def show_img(img_tensor):
    if len(img_tensor.shape) == 4:
        img = img_tensor.squeeze()
    else:
        img = img_tensor
    img = torch.movedim(img, 0, -1).type(torch.uint8).numpy()[:, :, ::-1]
    plt.imshow(img)
    plt.show()

def show_mask(mask_tensor):
    # shape height x width, single channel
    plt.imshow(mask_tensor)
    plt.show()

def show_pred_mask(model, img_tensor):
    if len(img_tensor.shape) == 4:
        source_img = img_tensor
    else:
        source_img = img_tensor.unsqueeze(0).to(DEVICE)

    model.eval()
    out = model(source_img)
    predicted = torch.argmax(out, dim=1)
    predicted = predicted.cpu().data.numpy()[0, :]
    plt.imshow(predicted)
    plt.show()

def show_all(model, img_tensor, mask_tensor, cmap='jet'):
    # regulate the image tensor
    if len(img_tensor.shape) == 4:
        img = img_tensor.squeeze()
        source_img = img_tensor
    else:
        img = img_tensor
        source_img = img_tensor.unsqueeze(0).to(DEVICE)

    # Raw image
    img = torch.movedim(img, 0, -1).type(torch.uint8).numpy()[:, :, ::-1]

    # Ground Truth mask
    mask = mask_tensor

    # predicted mask
    model.eval()
    out = model(source_img)
    predicted = torch.argmax(out, dim=1)
    predicted = predicted.cpu().data.numpy()[0, :]

    fig, axs = plt.subplots(1, 5, figsize=(20, 20), constrained_layout=True)

    axs[0].imshow(img)
    axs[0].set_title("Image")

    axs[1].imshow(mask)
    axs[1].set_title("Ground Truth")

    axs[2].imshow(predicted)
    axs[2].set_title("SegNet Outcome")

    img[:, :, 1] += (predicted * 255 * 0.15).astype(np.uint8)
    img[:, :, 0] += (predicted * 255 * 0.3).astype(np.uint8)
    axs[3].imshow(img, vmin=0, vmax=255)
    # axs[3].imshow(predicted, cmap=cmap, alpha=0.3)
    axs[3].set_title("SegNet Overlay")

    axs[4].imshow((predicted - mask.numpy()) ** 2)
    axs[4].set_title("Error")

    plt.show()


import threading
from io import BytesIO
from queue import Queue

import gcsfs
import h5py
import numpy as np
import pyrender
import skimage.io
import torch
import trimesh
from ml_collections import ConfigDict
from PIL import Image
from pyrender.trackball import Trackball
from rlbench.backend.const import DEPTH_SCALE
from rlbench.const import colors
from scipy.spatial.transform import Rotation
from skimage.color import gray2rgb, rgba2rgb

class RLBenchDataset(torch.utils.data.Dataset):
    @staticmethod
    def get_default_config(updates=None):
        config = ConfigDict()
        config.path = "gs://instruct-rl/dataset/variation"

        config.start_index = 0
        config.max_length = int(1e9)
        config.random_start = False

        config.image_size = 256

        config.state_key = ""
        config.state_dim = 0

        config.image_key = "front_rgb, left_shoulder_rgb, right_shoulder_rgb, wrist_rgb"

        config.action_key = "gripper_pose, gripper_open, ignore_collisions"
        config.action_dim = 7 + 1 + 1

        config.need_quat_normalize = "gripper_pose, gripper_pose_delta"

        config.use_bert_tokenizer = True
        config.tokenizer_max_length = 77

        if updates is not None:
            config.update(ConfigDict(updates).copy_and_resolve_references())
        return config

    def __init__(
        self,
        update,
        dataset_name="reach_target",
        start_offset_ratio=None,
        split="train",
    ):
        self.config = self.get_default_config(update)
        assert self.config.path != ""

        self.dataset_name = dataset_name

        if split == "train":
            path = f"{self.config.path}/{dataset_name}_train_shuffled.hdf5"
        elif split == "val":
            path = f"{self.config.path}/{dataset_name}_val_shuffled.hdf5"
        else:
            raise ValueError(f"Unknown split: {split}")
        if self.config.path.startswith("gs://"):
            self.h5_file = h5py.File(
                gcsfs.GCSFileSystem().open(path, cache_type="block"), "r"
            )
        else:
            self.h5_file = h5py.File(path, "r")

        if self.config.random_start:
            self.random_start_offset = np.random.default_rng().choice(len(self))
        elif start_offset_ratio is not None:
            self.random_start_offset = int(len(self) * start_offset_ratio) % len(self)
        else:
            self.random_start_offset = 0

        self.tokenizer = self.build_tokenizer()

    def __getstate__(self):
        return self.config, self.random_start_offset, self.dataset_name

    def __setstate__(self, state):
        config, random_start_offset, dataset_name = state
        self.__init__(config)
        self.random_start_offset = random_start_offset
        self.dataset_name = dataset_name

    def __len__(self):
        return min(
            self.h5_file["time"].shape[0] - self.config.start_index,
            self.config.max_length,
        )

    def process_index(self, index):
        index = (index + self.random_start_offset) % len(self)
        return index + self.config.start_index

    def __getitem__(self, index):
        index = self.process_index(index)
        res = {"image": {}}
        for key in self.config.image_key.split(", "):
            res["image"][key] = self.h5_file[key][index]
        if self.config.state_key != "":
            res["state"] = np.concatenate(
                [self.h5_file[k][index] for k in self.config.state_key.split(", ")],
                axis=-1,
            )
        res["action"] = np.concatenate(
            [
                self._normalize_quat(k, self.h5_file[k][index])
                for k in self.config.action_key.split(", ")
            ],
            axis=-1,
        )
        with BytesIO(self.h5_file["task_id"][index][0]) as fin:
            task_id = fin.read().decode("utf-8")
        variation_id = self.h5_file["variation_id"][index][0].item()
        instruct = get_instruct(task_id, variation_id)

        tokenized_instruct, padding_mask = self.tokenizer(instruct)

        res["instruct"] = tokenized_instruct
        res["padding_mask"] = padding_mask

        return res

    def _normalize_quat(self, name, quat):

        if name in self.config.need_quat_normalize.split(", "):
            return np.array(quat) / np.linalg.norm(quat, axis=-1, keepdims=True)
        else:
            return quat

    def build_tokenizer(self):
        use_bert_tokenizer = self.config.use_bert_tokenizer
        tokenizer_max_length = self.config.tokenizer_max_length

        if use_bert_tokenizer:
            import transformers

            tokenizer = transformers.BertTokenizer.from_pretrained("bert-base-uncased")
        else:
            from .models.openai import tokenizer

            tokenizer = tokenizer.build_tokenizer()

        def tokenizer_fn(instruct):
            if use_bert_tokenizer:
                if len(instruct) == 0:
                    tokenized_instruct = np.zeros(tokenizer_max_length, dtype=np.int32)
                    padding_mask = np.ones(tokenizer_max_length, dtype=np.float32)
                else:
                    encoded_instruct = tokenizer(
                        instruct,
                        padding="max_length",
                        truncation=True,
                        max_length=tokenizer_max_length,
                        return_tensors="np",
                        add_special_tokens=False,
                    )
                    tokenized_instruct = encoded_instruct["input_ids"][0].astype(
                        np.long
                    )
                    padding_mask = 1.0 - encoded_instruct["attention_mask"][0].astype(
                        np.float32
                    )
            else:
                tokenized_instruct = tokenizer(instruct)[0].astype(np.long)
                padding_mask = None
            return tokenized_instruct, padding_mask

        return tokenizer_fn

    @property
    def num_actions(self):
        return self.config.action_dim

    @property
    def obs_shape(self):
        res = {"image": {}}
        for key in self.config.image_key.split(", "):
            res["image"][key] = (256, 256, 3)
        if self.config.state_key != "":
            res["state"] = self.config.state_dim
        return res

def get_instruct(task, variation):
    # https://github.com/stepjam/RLBench/tree/master/rlbench/tasks
    if task == "stack_wine":
        return f"place the wine bottle on the wine rack."
    elif task == "take_umbrella_out_of_umbrella_stand":
        return f"grasping the umbrella by its handle, lift it up and out of the stand."
    elif task == "reach_target":
        return f"touch the {colors[variation]} ball with the panda gripper."
    elif task == "pick_and_lift":
        return f"pick up the {colors[variation]} block and lift it up to the target."
    elif task == "pick_up_cup":
        return f"grasp the {colors[variation]} cup and lift it."
    elif task == "put_rubbish_in_bin":
        return f"pick up the rubbish and leave it in the trash can."
    elif task == "take_lid_off_saucepan":
        return "grip the saucepan's lid and remove it from the pan."
    elif task == "open_drawer":
        OPTIONS = ["bottom", "middle", "top"]
        return f"grip the {OPTIONS[variation]} handle and pull the {OPTIONS[variation]} drawer open."
    elif task == "meat_off_grill":
        OPTIONS = ["chicken", "steak"]
        return f"pick up the {OPTIONS[variation]} and place it next to the grill."
    elif task == "put_item_in_drawer":
        OPTIONS = ["bottom", "middle", "top"]
        return f"open the {OPTIONS[variation]} drawer and place the block inside of it."
    elif task == "turn_tap":
        OPTIONS = ["left", "right"]
        return "grasp the {OPTIONS[variation]} tap and turn it."
    elif task == "put_groceries_in_cupboard":
        GROCERY_NAMES = [
            "crackers",
            "chocolate jello",
            "strawberry jello",
            "soup",
            "tuna",
            "spam",
            "coffee",
            "mustard",
            "sugar",
        ]
        return f"pick up the {GROCERY_NAMES[variation]} and place it in the cupboard."
    elif task == "place_shape_in_shape_sorter":
        SHAPE_NAMES = ["cube", "cylinder", "triangular prism", "star", "moon"]
        return f"pick up the {SHAPE_NAMES[variation]} and put it in the sorter."
    elif task == "light_bulb_in":
        return f"pick up the light bulb from the {colors[variation]} stand, lift it up to just above the lamp, then screw it down into the lamp in a clockwise fashion."
    elif task == "close_jar":
        return f"close the {colors[variation]} jar."
    elif task == "stack_blocks":
        MAX_STACKED_BLOCKS = 3
        color_index = int(variation / MAX_STACKED_BLOCKS)
        blocks_to_stack = 2 + variation % MAX_STACKED_BLOCKS
        color_name, color_rgb = colors[color_index]
        return (
            f"place {blocks_to_stack} of the {color_name} cubes on top of each other."
        )
    elif task == "put_in_safe":
        safe = {0: "bottom", 1: "middle", 2: "top"}
        return f"put the money away in the safe on the {safe[variation]} shelf."
    # elif task == "push_buttons":
    #     pass
    elif task == "insert_onto_square_peg":
        return f"put the ring on the {colors[variation]} spoke."
    elif task == "stack_cups":
        target_color_name, target_rgb = colors[variation]
        return f"stack the other cups on top of the {target_color_name} cup."
    elif task == "place_cups":  # 3 variations
        return f"place {variation + 1} cups on the cup holder."
    else:
        raise ValueError(f"Unknown task: {task}")

def discrete_euler_to_quaternion(discrete_euler, resolution):
    euluer = (discrete_euler * resolution) - 180
    return Rotation.from_euler("xyz", euluer, degrees=True).as_quat()

def get_cont_action(
    disc_action,
    vox_size=100,
    rotation_resolution=5,
    scene_bound=[-0.3, -0.5, 0.6, 0.7, 0.5, 1.6],
):
    coords = disc_action[:3]
    rot = disc_action[3:-1]
    grip = disc_action[-1]

    bound = np.array(scene_bound)

    res = (bound[3:] - bound[:3]) / vox_size
    trans = bound[:3] + res * coords + res / 2

    cont_action = np.concatenate(
        [trans, discrete_euler_to_quaternion(rot, rotation_resolution), grip]
    )
    # translation [0, vox_size - 1]
    # rotation [0, 360 / vox_size - 1]
    return cont_action


from flask import Flask, redirect, request, render_template, Blueprint, flash
from datetime import date, time
import repositories.gym_class_repository as gym_class_repository
import repositories.member_repository as member_repository
import repositories.instructor_repository as instructor_repository
import repositories.location_repository as location_repository
import repositories.attendance_repository as attendance_repository
from models.gym_class import GymClass
from models.member import Member
from models.instructor import Instructor

gym_class_blueprint = Blueprint("gym_class", __name__)

@gym_class_blueprint.route('/classes')
def classes():
    todays_date = str(date.today())
    gym_classes = gym_class_repository.select_all()
    return render_template('/gym_classes/index.html', title="Classes", classes=gym_classes, date=todays_date)

@gym_class_blueprint.route('/classes/<id>')
def gym_class(id):
    gym_class = gym_class_repository.select(id)
    members = member_repository.select_all()
    attendees = sorted(attendance_repository.select_by_class(gym_class), key=lambda attendance: attendance.member.last_name)

    number_attending = len(attendees)
    class_full = number_attending >= gym_class.location.capacity
    class_peak = gym_class.time >= time(9, 00, 00) and gym_class.time <= time(17, 30, 00)

    members_not_attending = []
    for member in members:
        if len(attendance_repository.select_by_class_and_member(gym_class, member)) == 0:
            members_not_attending.append(member)

    return render_template('/gym_classes/show.html',
        title=f"{gym_class.class_type} with {gym_class.instructor.name}",
        gym_class=gym_class,
        members=members_not_attending,
        attendees=attendees,
        class_full=class_full,
        number_attending=number_attending,
        class_peak=class_peak
    )

@gym_class_blueprint.route('/classes/<id>/edit')
def edit_class(id):
    todays_date = str(date.today())
    gym_class = gym_class_repository.select(id)
    all_instructors = instructor_repository.select_all()
    all_locations = location_repository.select_all()
    return render_template(
        '/gym_classes/edit.html',
        title="Edit class",
        gym_class=gym_class,
        instructors=all_instructors,
        locations=all_locations,
        date=todays_date
    )

@gym_class_blueprint.route('/classes/<id>', methods=['POST'])
def update_class(id):
    instructor = instructor_repository.select(request.form['instructor'])
    location = location_repository.select(request.form["location"])
    updated_class = GymClass(
        request.form['class_type'],
        instructor,
        request.form['date'],
        request.form['time'],
        request.form['duration'],
        location,
        id
    )
    gym_class_repository.update(updated_class)
    return redirect(f'/classes/{id}')

# New class
@gym_class_blueprint.route('/classes/new')
def new_class():
    todays_date = str(date.today())
    all_instructors = instructor_repository.select_all()
    all_locations = location_repository.select_all()
    return render_template('/gym_classes/new.html', title="Add new class", instructors=all_instructors, locations=all_locations, date=todays_date)

# Create class
@gym_class_blueprint.route('/classes/create', methods = ['POST'])
def create_class():
    instructor = instructor_repository.select(request.form['instructor'])
    location = location_repository.select(request.form["location"])
    new_gym_class = GymClass(
        request.form['class_type'],
        instructor,
        request.form['date'],
        request.form['time'],
        request.form['duration'],
        location
    )
    gym_class_repository.save(new_gym_class)
    return redirect('/classes')

# Delete class
@gym_class_blueprint.route('/classes/<id>/delete', methods=['POST'])
def destroy_class(id):
    return_to = request.form["return_to"]
    gym_class = gym_class_repository.select(id)
    instructor_id = gym_class.instructor.id

    gym_class_repository.delete(id)

    if return_to == "instructors":
        return redirect(f'/instructors/{instructor_id}')
    else:
        return redirect('/classes')


import os
import pathlib
import typing as tp

from pyvcs.index import read_index, update_index  # type: ignore
from pyvcs.objects import commit_parse  # type: ignore
from pyvcs.objects import find_object  # type: ignore
from pyvcs.objects import find_tree_files  # type: ignore
from pyvcs.objects import read_object  # type: ignore
from pyvcs.objects import read_tree  # type: ignore
from pyvcs.refs import get_ref, is_detached, resolve_head, update_ref  # type: ignore
from pyvcs.tree import commit_tree, write_tree  # type: ignore

def add(gitdir: pathlib.Path, paths: tp.List[pathlib.Path]) -> None:
    for path in paths:
        if path.is_file():
            update_index(gitdir, [path], write=True)
        if path.is_dir():
            add(gitdir, list(path.glob("*")))

def commit(gitdir: pathlib.Path, message: str, author: tp.Optional[str] = None) -> str:
    tree = write_tree(gitdir, read_index(gitdir))
    com = commit_tree(gitdir, tree, message, author=author)
    return com

def checkout(gitdir: pathlib.Path, obj_name: str) -> None:
    for entry in read_index(gitdir):
        try:
            os.remove(entry.name)
        except FileNotFoundError:
            pass
    com = commit_parse(read_object(obj_name, gitdir)[1])
    stopped = False
    while not stopped:
        trees: tp.List[tp.Tuple[pathlib.Path, tp.List[tp.Tuple[int, str, str]]]]
        trees = [(gitdir.parent, read_tree(read_object(com["tree"], gitdir)[1]))]
        while trees:
            tree_path, tree_content = trees[-1]
            del trees[-1]
            for file_data in tree_content:
                fmt, data = read_object(file_data[2], gitdir)
                if fmt == "tree":
                    trees.append((tree_path / file_data[1], read_tree(data)))
                    if not (tree_path / file_data[1]).exists():
                        (tree_path / file_data[1]).mkdir()
                else:
                    if not (tree_path / file_data[1]).exists():
                        with (tree_path / file_data[1]).open("wb") as f:
                            f.write(data)
                        (tree_path / file_data[1]).chmod(int(str(file_data[0]), 8))
        if "parent" in com:
            parse = commit_parse((read_object(com["parent"], gitdir)[1]))
            com[parse[0]] = parse[1]
        else:
            stopped = True
    for dir in gitdir.parent.glob("*"):
        if dir != gitdir and dir.is_dir():
            try:
                os.removedirs(dir)
            except OSError:
                continue


"""
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


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


#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# author:haiton
# datetime:18-9-13 下午1:35
import os
import pickle
import numpy as np
import torch
import time
import argparse
import json
from torch import nn
from tqdm import tqdm
from model.model import RNNModel
from utils.dataset import DefSeqDataset
from torch.utils.data import DataLoader
from utils.utils import get_testloader, get_time_dif

parser = argparse.ArgumentParser(description='Pytorch Definition Sequence Model')
parser.add_argument('--model', type=str, default='GRU',
                    help='type of recurrent network(RNN,LSTM,GRU)')
parser.add_argument('--emdim', type=int, default=300,
                    help='size of word embeddings')
parser.add_argument('--hidim', type=int, default=300,
                    help='numbers of hidden units per layer')
parser.add_argument('--nlayers', type=int, default=2,
                    help='number of layers')
parser.add_argument('--lr', type=int, default=0.001,
                    help='initial learning rate')
parser.add_argument('--clip', type=int, default='5',
                    help='gradient clipping')
parser.add_argument('--epochs', type=int, default=40,
                    help='upper epoch limit')
parser.add_argument('--batch_size', type=int, default=50,
                    help='batch size')
parser.add_argument('--dropout', type=float, default=0.0,
                    help='dropout applied to layers(0 = no dropout)')
parser.add_argument('--wdecay', type=float, default=1.2e-6,
                    help='weight decay applied to all weights')
parser.add_argument('--use_i', action='store_true',
                    help='use model I')
parser.add_argument('--use_h', action='store_true',
                    help='use model H')
parser.add_argument('--use_g', action='store_true',
                    help='use model G')
parser.add_argument('--tied', action='store_true',
                    help='tie the word embedding and softmax weights')
parser.add_argument('--seed', type=int, default=22222,
                    help='random seed')
parser.add_argument('--cuda', action='store_true',
                    help='use CUDA')
parser.add_argument('--use_ch', action='store_true',
                    help='use character level CNN')
parser.add_argument('--use_he', action='store_true',
                    help='use hypernym embeddings')
parser.add_argument('--temperature', type=float, default=1.0,
                    help='temperature - higher will increase diversity')
args = parser.parse_args()
args.tied = False

args.use_ch = False
args.use_he = False
args.use_i = False
args.use_h = False
args.use_g = True

CHAR_EMB_DIM = 20
CHAR_HID_DIM = 20

saves_dir = "./data/processed"  # directory to save processdata
model_save_dir = 'checkpoints/'  # directory to save model
gen_dir = 'gen/'  # directory to save generation definitions

# Set the random seed manually for reproducibility
np.random.seed(args.seed)
torch.manual_seed(args.seed)
if torch.cuda.is_available():
    if not args.cuda:
        print('WARNING:You have a CUDA device,so you should probably run with --cuda')
    else:
        torch.cuda.manual_seed(args.seed)
device = torch.device('cuda' if args.cuda else 'cpu')

def get_trainloader(filepath):
    with open(filepath, 'rb') as f:
        train = pickle.load(f)
    train_set = DefSeqDataset(train, mode='train')
    char_max_len = len(train_set[0]['chars'])
    train_loader = DataLoader(
        dataset=train_set,
        batch_size=args.batch_size,
        shuffle=True,
        num_workers=2
    )
    return train_loader, char_max_len

def get_validloader(filepath):
    with open(filepath, 'rb') as f:
        valid = pickle.load(f)
    valid_set = DefSeqDataset(valid, mode='valid')
    valid_loader = DataLoader(
        dataset=valid_set,
        batch_size=args.batch_size,
        shuffle=True,
        num_workers=2
    )
    return valid_loader

def train():
    with open(os.path.join(saves_dir, 'word2id.pkl'), 'rb') as f:
        vocab = pickle.load(f)
        f.close()
    with open(os.path.join(saves_dir, 'id2word.pkl'), 'rb') as f:
        id2word = pickle.load(f)
        f.close()
    with open(os.path.join(saves_dir, 'word_embedding.pkl'), 'rb') as f:
        word_embedding = pickle.load(f)
        f.close()
    train_loader, char_max_len = get_trainloader('./data/processed/train.pkl')
    valid_loader = get_validloader('./data/processed/valid.pkl')
    # test_loader = get_testloader('./data/processed/play.pkl')
    char2idx = json.loads(open('./data/processed/char2idx.js').read())
    char_data = {
        'char_vocab_size': len(char2idx) + 1,
        'char_emb_dim': CHAR_EMB_DIM,
        'char_hid_dim': CHAR_HID_DIM,
        'char_len': char_max_len
    }
    print('=========model architecture==========')
    model = RNNModel(
        args.model, len(vocab), args.emdim, args.hidim, args.nlayers, args.tied, args.dropout, device, word_embedding,
        use_ch=args.use_ch, use_he=args.use_he, use_i=args.use_i, use_h=args.use_h, use_g=args.use_g, **char_data).to(
        device)
    print(model)
    print('=============== end =================')
    loss_fn = nn.CrossEntropyLoss(ignore_index=0)
    parameters = filter(lambda p: p.requires_grad, model.parameters())
    optimizer = torch.optim.Adam(parameters, args.lr,weight_decay=args.wdecay)
    print('Training and evaluating...')
    start_time = time.time()
    if not os.path.exists(model_save_dir):
        os.makedirs(model_save_dir)
    best_ppl = 9999999
    last_improved = 0
    require_improvement = 5
    for epoch in range(args.epochs):
        model.training = True
        total_loss = 0.0
        loss_epoch = []
        for batch, inp in enumerate(tqdm(train_loader, desc='Epoch: %03d' % (epoch + 1), leave=False)):
            data = {
                'word': torch.tensor(inp['word'], dtype=torch.long).to(device),
                'seq': torch.tensor(torch.t(inp['seq']), dtype=torch.long).to(device),
                'chars': torch.tensor(inp['chars'], dtype=torch.long).to(device),
                'hnym': torch.tensor(inp['hnym'], dtype=torch.long).to(device),
                'hnym_weights': torch.tensor(inp['hnym_weights'], dtype=torch.float).to(device)
            }

            targets = torch.tensor(torch.t(inp['target']), dtype=torch.long).to(device)
            output, hidden = model(data, None)
            loss = loss_fn(output, targets.view(-1))
            optimizer.zero_grad()
            total_loss += loss.item()
            loss_epoch.append(loss.item())
            loss.backward()
            # `clip_grad_norm`
            torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
            optimizer.step()
        train_loss = np.mean(loss_epoch)
        train_ppl = np.exp(train_loss)
        valid_loss, valid_ppl = evaluate(model, valid_loader, device)
        # generate(model, test_loader, id2word, epoch + 1, 20)

        if valid_ppl < best_ppl:
            best_ppl = valid_ppl
            last_improved = epoch
            torch.save(model.state_dict(), model_save_dir +
                       'defseq_model_params_%s_min_ppl.pkl' % (epoch + 1)
                       )
            improved_str = '*'
        else:
            torch.save(model.state_dict(), model_save_dir +
                       'defseq_model_params_%s_ppl.pkl' % (epoch + 1)
                       )
            improved_str = ''
        time_dif = get_time_dif(start_time)
        msg = 'Epoch: {0:>6},Train Loss: {1:>6.6}, Train Ppl: {2:>6.6},' \
              + ' Val loss: {3:>6.6}, Val Ppl: {4:>6.6},Time:{5} {6}'
        print(msg.format(epoch + 1, train_loss, train_ppl, valid_loss, valid_ppl, time_dif, improved_str))
        if epoch - last_improved > require_improvement:
            print("No optimization for a long time, auto-stopping...")
            break
    return 1

def evaluate(model, dataloader, device='cpu'):
    model.training = False
    loss_fn = nn.CrossEntropyLoss(ignore_index=0)
    with torch.no_grad():
        total_loss = []
        for inp in dataloader:
            data = {
                'word': torch.tensor(inp['word'], dtype=torch.long).to(device),
                'seq': torch.tensor(torch.t(inp['seq']), dtype=torch.long).to(device),
                'chars': torch.tensor(inp['chars'], dtype=torch.long).to(device),
                'hnym': torch.tensor(inp['hnym'], dtype=torch.long).to(device),
                'hnym_weights': torch.tensor(inp['hnym_weights'], dtype=torch.float).to(device)
            }
            targets = torch.tensor(torch.t(inp['target']), dtype=torch.long).to(device)
            output, hidden = model(data, None)
            loss = loss_fn(output, targets.view(-1))
            total_loss.append(loss.item())
    return np.mean(total_loss), np.exp(np.mean(total_loss))

def generate(model, dataloader, idx2word, num, word_len=50):
    model.training = False
    for inp in tqdm(dataloader, desc='Generate definitions', leave=False):
        word_list = []
        data = {
            'word': torch.tensor(inp['word'], dtype=torch.long).to(device),
            'seq': torch.tensor(torch.t(inp['seq']), dtype=torch.long).to(device),
            'chars': torch.tensor(inp['chars'], dtype=torch.long).to(device),
            'hnym': torch.tensor(inp['hnym'], dtype=torch.long).to(device),
            'hnym_weights': torch.tensor(inp['hnym_weights'], dtype=torch.float).to(device)
        }
        if not os.path.exists(gen_dir):
            os.makedirs(gen_dir)
        def_word = [idx2word[torch.tensor(inp['word'], dtype=torch.long).to(device)], "\t"]
        word_list.extend(def_word)
        hidden = None
        for i in range(word_len):
            output, hidden = model(data, hidden)
            word_weights = output.squeeze().div(args.temperature).exp().cpu()
            word_idx = torch.argmax(word_weights)
            if word_idx == 3:
                break
            else:
                data['seq'].fill_(word_idx)
                if word_idx != 2:
                    word = idx2word[word_idx]
                    word_list.append(word)
        with open(gen_dir + "gen_%s.txt" % (num), "a") as f:
            for item in word_list:
                f.write(item + " ")
            f.write("\n")
            f.close()
    return 1

if __name__ == "__main__":
    print('=============user config=============')
    for key, value in sorted(args.__dict__.items()):
        print('{key}:{value}'.format(key=key, value=value))
    print('=============== end =================')
    train()


# -*- 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]))


import datetime
import update
from bs4 import BeautifulSoup

TOP_NAV = """

    HOME

    NEWS

    OPINION

    CRITIC'S CORNER

    CULTURE & ILLUSTRATIONS

    <svg class="w-6 h-6" fill="none" stroke="currentColor" style="padding: 2px; background-color: black; color: white; display:inline-block;" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
     <path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
     </path>
    </svg>

    <input id="searchbar" onkeyup="searchbar()" placeholder="Search..." style="color: black;" type="text"/>

"""

BOTTOM_NAV = """

     CATEGORIES

     News

     Opinion

     Critic's Corner

     Culture & Illustrations

     QUICK LINKS

     Book Reviews

     Movie Reviews

     Short Stories

     Horoscopes

     Comics

    <svg height="48px" viewbox="0 0 48 48" width="48px" xmlns="http://www.w3.org/2000/svg">
     <radialgradient cx="19.38" cy="42.035" gradientunits="userSpaceOnUse" id="yOrnnhliCrdS2gy~4tD8ma" r="44.899">
      <stop offset="0" stop-color="#fd5">
      </stop>
      <stop offset=".328" stop-color="#ff543f">
      </stop>
      <stop offset=".348" stop-color="#fc5245">
      </stop>
      <stop offset=".504" stop-color="#e64771">
      </stop>
      <stop offset=".643" stop-color="#d53e91">
      </stop>
      <stop offset=".761" stop-color="#cc39a4">
      </stop>
      <stop offset=".841" stop-color="#c837ab">
      </stop>
     </radialgradient>
     <path d="M34.017,41.99l-20,0.019c-4.4,0.004-8.003-3.592-8.008-7.992l-0.019-20	c-0.004-4.4,3.592-8.003,7.992-8.008l20-0.019c4.4-0.004,8.003,3.592,8.008,7.992l0.019,20	C42.014,38.383,38.417,41.986,34.017,41.99z" fill="url(#yOrnnhliCrdS2gy~4tD8ma)">
     </path>
     <radialgradient cx="11.786" cy="5.54" gradienttransform="matrix(1 0 0 .6663 0 1.849)" gradientunits="userSpaceOnUse" id="yOrnnhliCrdS2gy~4tD8mb" r="29.813">
      <stop offset="0" stop-color="#4168c9">
      </stop>
      <stop offset=".999" stop-color="#4168c9" stop-opacity="0">
      </stop>
     </radialgradient>
     <path d="M34.017,41.99l-20,0.019c-4.4,0.004-8.003-3.592-8.008-7.992l-0.019-20	c-0.004-4.4,3.592-8.003,7.992-8.008l20-0.019c4.4-0.004,8.003,3.592,8.008,7.992l0.019,20	C42.014,38.383,38.417,41.986,34.017,41.99z" fill="url(#yOrnnhliCrdS2gy~4tD8mb)">
     </path>
     <path d="M24,31c-3.859,0-7-3.14-7-7s3.141-7,7-7s7,3.14,7,7S27.859,31,24,31z M24,19c-2.757,0-5,2.243-5,5	s2.243,5,5,5s5-2.243,5-5S26.757,19,24,19z" fill="#fff">
     </path>
     <circle cx="31.5" cy="16.5" fill="#fff" r="1.5">
     </circle>
     <path d="M30,37H18c-3.859,0-7-3.14-7-7V18c0-3.86,3.141-7,7-7h12c3.859,0,7,3.14,7,7v12	C37,33.86,33.859,37,30,37z M18,13c-2.757,0-5,2.243-5,5v12c0,2.757,2.243,5,5,5h12c2.757,0,5-2.243,5-5V18c0-2.757-2.243-5-5-5H18z" fill="#fff">
     </path>
    </svg>

    <svg height="48" viewbox="0 0 48 48" width="48" x="0px" xmlns="http://www.w3.org/2000/svg" y="0px">
     <path d="M34,42H14c-4.411,0-8-3.589-8-8V14c0-4.411,3.589-8,8-8h20c4.411,0,8,3.589,8,8v20 C42,38.411,38.411,42,34,42z" fill="#1e88e5">
     </path>
     <path d="M35.926,17.488L29.414,24l6.511,6.511C35.969,30.347,36,30.178,36,30V18 C36,17.822,35.969,17.653,35.926,17.488z M26.688,23.899l7.824-7.825C34.347,16.031,34.178,16,34,16H14 c-0.178,0-0.347,0.031-0.512,0.074l7.824,7.825C22.795,25.38,25.205,25.38,26.688,23.899z M24,27.009 c-1.44,0-2.873-0.542-3.99-1.605l-6.522,6.522C13.653,31.969,13.822,32,14,32h20c0.178,0,0.347-0.031,0.512-0.074l-6.522-6.522 C26.873,26.467,25.44,27.009,24,27.009z M12.074,17.488C12.031,17.653,12,17.822,12,18v12c0,0.178,0.031,0.347,0.074,0.512 L18.586,24L12.074,17.488z" fill="#fff">
     </path>
    </svg>

    <svg height="100" style="padding-bottom: 100%; width: 50px;" viewbox="0 0 100 100" width="100" x="0px" xmlns="http://www.w3.org/2000/svg" y="0px">
     <circle cx="52" cy="52" opacity=".35" r="44">
     </circle>
     <circle cx="50" cy="50" fill="#f2f2f2" r="44">
     </circle>
     <path d="M50,12.5c-20.711,0-37.5,16.789-37.5,37.5S29.289,87.5,50,87.5S87.5,70.711,87.5,50 S70.711,12.5,50,12.5z" fill="#707cc0">
     </path>
     <path d="M60.161,83.936c0-1.122,0.042-4.813,0.042-9.389c0-3.192-1.095-5.281-2.324-6.338 c7.624-0.847,15.626-3.74,15.626-16.888c0-3.736-1.324-6.791-3.518-9.184c0.352-0.866,1.527-4.346-0.341-9.057 c0,0-2.868-0.92-9.402,3.508c-2.734-0.759-5.662-1.139-8.568-1.152c-2.91,0.013-5.838,0.393-8.568,1.152 c-6.538-4.429-9.411-3.508-9.411-3.508c-1.862,4.712-0.687,8.192-0.336,9.057c-2.189,2.393-3.523,5.448-3.523,9.184 c0,13.115,7.99,16.051,15.589,16.915c-0.978,0.856-1.862,2.364-2.173,4.575c-1.95,0.876-6.907,2.386-9.96-2.844 c0,0-1.808-3.285-5.242-3.527c0,0-3.342-0.043-0.235,2.08c0,0,2.244,1.053,3.8,5.006c0,0,2.009,6.656,11.529,4.588 c0.017,2.856,0.046,5.008,0.046,5.821c0,0.385-0.122,0.792-0.383,1.115C45.945,86.292,49.3,87,52.807,87 c2.981,0,5.853-0.509,8.576-1.417C60.502,85.37,60.161,84.613,60.161,83.936z" fill="#f2f2f2">
     </path>
     <path d="M50,89c-21.505,0-39-17.495-39-39s17.495-39,39-39s39,17.495,39,39S71.505,89,50,89z M50,14 c-19.851,0-36,16.149-36,36s16.149,36,36,36s36-16.149,36-36S69.851,14,50,14z" fill="#40396e">
     </path>
    </svg>

"""

#uploading file to github
def upload(filename, file):
    git_file = filename.replace(':', '')
    update.repo.create_file(git_file, "committing new article file", "" + file, branch="main")

#updating javascript file
class UpdateJs():
    def __init__(self):
        self.newfilename = ""
        self.newpath = ""

        self.deletefile = ""
        self.deletepath = ""

    def updatejs(self, file, change):
        path = file
        f = update.repo.get_contents(path)
        update.repo.update_file(path, "updating nav bar", change, f.sha)

    def newfile(self, name, path): #add new file to search bar
        self.newfilename = name
        self.newpath = path

        fread = update.repo.get_contents("js/nav.js").decoded_content.decode()
        old = fread.split("\n")
        new = (old[0].replace('\n', ''))[:len(old[0])-2] + ", [\"" + name + "\", \"" + path + "\"]];"
        file_arr = fread.split("\n")

        change = new.replace('\n', '') + "\n"
        for x in range(1,len(file_arr) - 1):
            change = change + file_arr[x] + "\n"
        change = change + file_arr[len(file_arr) - 1]
        self.updatejs("js/nav.js", change)

#creating types of pages
class Text_Based():
    def __init__(self, genre, date, title, subtitle, author, body, img_filename, photographer, isfeatured):
        self.title = title
        self.genre = genre

        if img_filename == "": #generate html file without img
            self.content = self.file_content(self.format_head(date,genre,author,title, isfeatured),
                self.format_intro(genre, title, subtitle, author, date),
                "no image", self.format_body(body))
        else:
            self.content = self.file_content(self.format_head(date,genre,author,title,isfeatured), #generate html file
                self.format_intro(genre, title, subtitle, author, date),
                self.format_img(img_filename, photographer), self.format_body(body))

    def file_content(self, head, intro, img_name, body):
        global TOP_NAV
        global BOTTOM_NAV
        file_content = "<!DOCTYPE html>\n"
        file_content = file_content + "\t" + head + "\n"
        file_content = file_content + TOP_NAV + """\n\n\n"""
        file_content = file_content + """
\n\n""" + intro + """\n"""

        if not img_name == "no image":
            file_content = file_content + "\n" + img_name + "\n"

        file_content = file_content + "\n" + body + "
\n" + BOTTOM_NAV + "\n"

        return file_content

    def format_head(self, date, genre, author, title, isfeatured):
        feature = ""
        if isfeatured == 1:
            feature = "yes"
        else:
            feature = "no"

        META = "\t<meta name = "
        head_content = "\n" + META + "\"date\" content = \"" + date + "\">\n"
        head_content = head_content + META + "\"genre\" content = \"" + genre + "\">\n"
        head_content = head_content + META + "\"author\" content = \"" + author + "\">\n"
        head_content = head_content + META + "\"title\" content = \"" + title + "\">\n"
        head_content = head_content + META + "\"feature\" content = \"" + feature + "\">\n"
        head_content = head_content + "\t<title>" + title + "</title>\n"
        head_content = head_content + "\t<link href = \"https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css\" rel = \"stylesheet\">\n\t<link href=\"riverdale spectator.css\" rel=\"stylesheet\">\n\t\n<link rel=\"icon\" type=\"image/x-icon\" href=\"images/tab icon.png\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, shrink-to-fit=no\">"
        return head_content

    def format_intro(self, genre, title, subtitle, author, date):
        intro_contents = "
" + genre + "
\n"
        intro_contents = intro_contents + "
" + title + "
\n"

        if "BOOK REVIEWS" in self.genre.upper() or "MOVIE REVIEWS" in self.genre.upper():
            intro_contents = intro_contents + "
" + subtitle + "
\n"
        else:
            intro_contents = intro_contents + "
" + subtitle + "
\n"
        intro_contents = intro_contents + "
" + author + "
\n"
        intro_contents = intro_contents + "
" + date + "
\n"
        intro_contents = intro_contents + "
\n"
        return intro_contents

    def format_img(self, img_filename, photographer):
        if img_filename == "no image":
            return ""
        else:
            tmp = ("images" + "\u005c" + img_filename).replace('\n', '')
            img_content = "\n"
            img_content = img_content + "
Photographer: "+ photographer+"
\n"

        return img_content

    def isheading(self, word_arr):
        count_upper = 0
        count_lower = 0

        for i in word_arr:
            if i[0:1].isupper():
                count_upper += 1
            else:
                count_lower += 1

        sentence = " ".join(word_arr)

        if "★" in sentence or count_upper > count_lower:
            return 1 #true
        else:
            return 0 #false

    def format_body(self, txt):
        lines_txt = txt.split("\n")
        #html for body paragraph
        body_contents = ""

        for x in reversed(range(len(lines_txt))):
            if lines_txt[x].replace(" ", "") == "":
                lines_txt.pop(x)
            else:
                lines_txt[x] = lines_txt[x].lstrip()

        for x in range(len(lines_txt)):
            if x == 0 and not self.genre == "Horoscopes":
                if("BOOK REVIEWS" in self.genre.upper() or "MOVIE REVIEWS" in self.genre.upper()):
                    word_arr = lines_txt[x].split()
                    if self.isheading(word_arr) == 1:
                        body_contents += """
""" + lines_txt[x] + "
\n"
                    else:
                        body_contents += """
""" + lines_txt[x] + "
\n"
                else:
                    body_contents = """
""" + lines_txt[x] + "
\n"

            elif(self.genre == "Horoscopes"):
                tmp_arr = lines_txt[x].split(" ")
                body_contents += "
" + "" + tmp_arr[0] + ""
                tmp_arr.pop(0)
                body_contents += " ".join(tmp_arr) + "
\n"
            elif("BOOK REVIEWS" in self.genre.upper() or "MOVIE REVIEWS" in self.genre.upper()):
                MAX_CHAR = 75
                if len(lines_txt) < 75:
                    word_arr = lines_txt[x].split()
                    if self.isheading(word_arr) == 1:
                        body_contents += """
""" + lines_txt[x] + "
\n"
                    else:
                        body_contents += """
""" + lines_txt[x] + "
\n"
                else:
                    body_contents += """
""" + lines_txt[x] + "
\n"
            else:
                body_contents += """
""" + lines_txt[x] + "
\n"

        return body_contents

    def get_file(self):
        contents = BeautifulSoup(self.content,'html.parser')
        return (contents.prettify())

    def get_filname(self):
        filename = (self.title + " " + str(datetime.datetime.now().strftime("%f")) + ".html").replace(':', '').replace('%', '').replace('#', '').replace('&', '').replace('{', '').replace('}', '').replace('\u005c', '').replace('/', '').replace('>', '').replace('<', '').replace('?', '').replace('*', '').replace('$', '').replace('\'', '') .replace('\"', '').replace('@', '').replace('+', '').replace('=', '').replace('|', '').replace('`', '').replace(')', '').replace('(', '')
        return filename.replace('\n', '')

class Comic():          #genre, date, title, subtitle, author, img_filename, isfeatured
    def __init__(self, genre, date, title, subtitle, author, img_filename, isfeatured):
        self.title = title
        self.genre = genre

        self.content = self.file_content(self.format_head(date,genre,author,title,isfeatured), #generate html file
            self.format_intro(genre, title, subtitle, author, date), self.format_img(img_filename))

    def file_content(self, head, intro, img_name):
        global TOP_NAV
        global BOTTOM_NAV
        file_content = "<!DOCTYPE html>\n"
        file_content += "\t" + head + "\n"
        file_content += TOP_NAV + """\n\n\n"""
        file_content += """
\n\n""" + intro + """\n"""
        file_content += "\n" + img_name + "\n"

        file_content += "
\n" + BOTTOM_NAV + "\n"

        return file_content

    def format_head(self, date, genre, author, title, isfeatured):
        feature = ""
        if isfeatured == 1:
            feature = "yes"
        else:
            feature = "no"

        META = "\t<meta name = "
        head_content = "\n" + META + "\"date\" content = \"" + date + "\">\n"
        head_content += META + "\"genre\" content = \"" + genre + "\">\n"
        head_content += META + "\"author\" content = \"" + author + "\">\n"
        head_content += META + "\"title\" content = \"" + title + "\">\n"
        head_content += META + "\"feature\" content = \"" + feature + "\">\n"
        head_content += "\t<title>" + title + "</title>\n"
        head_content += "\t<link href = \"https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css\" rel = \"stylesheet\">\n\t<link href=\"riverdale spectator.css\" rel=\"stylesheet\">\n\t\n<link rel=\"icon\" type=\"image/x-icon\" href=\"images/tab icon.png\">\n"
        return head_content

    def format_intro(self, genre, title, subtitle, author, date):
        intro_contents = "
" + genre + "
\n"
        intro_contents += "
" + title + "
\n"
        intro_contents += "
" + subtitle + "
\n"
        intro_contents += "
" + author + "
\n"
        intro_contents += "
" + date + "
\n"
        intro_contents += "
\n"
        return intro_contents

    def format_img(self, img_filename):
        tmp = ("images" + "\u005c" + img_filename).replace('\n', '')
        img_content = "\n"
        return img_content

    def get_file(self):
        contents = BeautifulSoup(self.content,'html.parser')
        return (contents.prettify())

    def get_filname(self):
        filename = (self.title + " " + str(datetime.datetime.now().strftime("%f")) + ".html").replace(':', '').replace('%', '').replace('#', '').replace('&', '').replace('{', '').replace('}', '').replace('\u005c', '').replace('/', '').replace('>', '').replace('<', '').replace('?', '').replace('*', '').replace('$', '').replace('\'', '') .replace('\"', '').replace('@', '').replace('+', '').replace('=', '').replace('|', '').replace('`', '').replace(')', '').replace('(', '')
        return filename.replace('\n', '')


# 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()


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 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}")


from celery import Celery
from src.config import *

# A display message when the app starts
print("[INFO] Keep Calm n Enjoy the drill...")

# Function to create celery
def make_celery(app_name=__name__):
    return Celery(
        app_name,
        broker=BROKER_URL,
        backend=BACKEND_URL
    )

celery = make_celery()


from django.urls import path

from Shop import views

urlpatterns = [
    path("", views.index, name="shophome"),
    path("about/", views.about, name="AboutUs"),
    path("contact/", views.contact, name="ContactUs"),
    path("tracker/", views.tracker, name="Track"),
    path("search/", views.search, name="Search"),
    path("productview/", views.prodview, name="ProdView"),
    path("checkout/", views.checkout, name="Checkout"),
]


# -*- 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')


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()]))