# coding=utf-8
# Copyright 2020 The HuggingFace Datasets Authors and the current dataset script contributor.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""TODO: Add a description here."""

from __future__ import absolute_import, division, print_function

import copy
import xml.etree.ElementTree as etree

import datasets

logger = datasets.logging.get_logger(__name__)

# Find for instance the citation on arxiv or on the dataset repo/website
_CITATION = """\
"""

# You can copy an official description
_DESCRIPTION = """\
NLM produces a baseline set of MEDLINE/PubMed citation records in XML format for download on an annual basis. The annual baseline is released in December of each year. Each day, NLM produces update files that include new, revised and deleted citations. See our documentation page for more information.
"""

_HOMEPAGE = "https://www.nlm.nih.gov/databases/download/pubmed_medline.html"

_LICENSE = ""

# TODO: Add link to the official dataset URLs here
# The HuggingFace dataset library don't host the datasets but only point to the original files
# This can be an arbitrary nested dict/list of URLs (see below in `_split_generators` method)
_URLs = [f"ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline/pubmed21n{i:04d}.xml.gz" for i in range(1, 1063)]

# Copyright Ferry Boender, released under the MIT license.
# Modified by @Narsil to handle more oddities
def deepupdate(target, src):
    """Deep update target dict with src
    For each k,v in src: if k doesn't exist in target, it is deep copied from
    src to target. Otherwise, if v is a list, target[k] is extended with
    src[k]. If v is a set, target[k] is updated with v, If v is a dict,
    recursively deep-update it.

    Examples:
    >>> t = {'name': 'Ferry', 'hobbies': ['programming', 'sci-fi']}
    >>> deepupdate(t, {'hobbies': ['gaming']})
    >>> print(t)
    {'name': 'Ferry', 'hobbies': ['programming', 'sci-fi', 'gaming']}
    """
    for k, v in src.items():
        if k in target and isinstance(target[k], int) and isinstance(v, str):
            try:
                v = int(v)
            except Exception:
                pass
        if k in target and type(target[k]) != type(v):
            logger.warning(f"Ignoring field {k} it's a {type(v)} and we expect a {type(target[k])}")
            continue

        if type(v) == list:
            if k not in target:
                target[k] = copy.deepcopy(v)
            elif isinstance(target[k], list):
                target[k].extend(v)
            elif isinstance(target[k], str):
                # Very special case to handle `AbstractText` which sometimes end up
                # being a list.
                new_v = " ".join(el for el in v if isinstance(el, str))
                target[k] = new_v
            else:
                logger.warning(f"Ignoring field {k} it's a {type(v)} and we expect a {type(target[k])}")
        elif type(v) == dict:
            if k not in target:
                target[k] = copy.deepcopy(v)
            elif isinstance(target[k], dict):
                deepupdate(target[k], v)
            else:
                logger.warning(f"Ignoring field {k} it's a {type(v)} and we expect a {type(target[k])}")
        elif type(v) == set:
            if k not in target:
                target[k] = v.copy()
            elif isinstance(target[k], set):
                target[k].update(v.copy())
            else:
                logger.warning(f"Ignoring field {k} it's a {type(v)} and we expect a {type(target[k])}")
        else:
            if isinstance(target[k], (list, tuple, dict)):
                logger.warning(f"Ignoring field {k} it's a {type(v)} and we expect a {type(target[k])}")
                continue

            target[k] = copy.copy(v)

def default_date():
    return {"Year": 0, "Month": 0, "Day": 0}

def default_inline_article():
    return {
        # 'Journal': Journal,
        "Abstract": {"AbstractText": ""},
        "ArticleTitle": "",
        # 'Pagination': {'MedlinePgn': datasets.Value('string')},
        "AuthorList": {"Author": []},
        "Language": "",
        "GrantList": {
            "Grant": [],
        },
        "PublicationTypeList": {"PublicationType": []},
    }

def default_article():
    return {
        "MedlineCitation": {
            "PMID": 0,
            "DateCompleted": default_date(),
            "NumberOfReferences": 0,
            "DateRevised": default_date(),
            "Article": default_inline_article(),
            "MedlineJournalInfo": {"Country": ""},
            "ChemicalList": {"Chemical": []},
            "CitationSubset": "",
            "MeshHeadingList": {"MeshHeading": []},
        },
        "PubmedData": {
            "ArticleIdList": [{"ArticleId": []}],
            "PublicationStatus": "",
            "History": {"PubMedPubDate": []},
            "ReferenceList": [],
        },
    }

class Pubmed(datasets.GeneratorBasedBuilder):
    """Pubmed citations records"""

    BUILDER_CONFIGS = [
        datasets.BuilderConfig(name="2021", description="The 2021 annual record", version=datasets.Version("1.0.0")),
    ]

    # FILLED automatically from features
    SIMPLE_KEYS = {"PubmedArticleSet"}
    LIST_KEYS = {"PubmedArticle"}
    IGNORE_KEYS = set()

    def fill_keys_from_features(self, features):
        if isinstance(features, dict):
            for key, value in features.items():
                if isinstance(value, datasets.Sequence):
                    self.LIST_KEYS.add(key)
                    self.fill_keys_from_features(value.feature)
                else:
                    self.SIMPLE_KEYS.add(key)
                    self.fill_keys_from_features(value)

    def xml_to_dictionnary(self, parentElement):
        data = {}
        if parentElement.tag in {"AbstractText", "ArticleTitle"}:
            # XXX
            # Very special case, it will contain html leading to having very odd structure
            tag = parentElement.tag
            string = etree.tostring(parentElement).decode("utf-8").strip()
            inner_string = string[len(f"<{tag}>") : -len(f"</{tag}>")]
            return {parentElement.tag: inner_string}

        for child in list(parentElement):
            child.text = child.text if (child.text is not None) else " "
            key = child.tag
            if len(child) == 0:
                value = child.text.strip()
            else:
                value = self.xml_to_dictionnary(child)
                if isinstance(value, dict) and set(value.keys()) == {key}:
                    value = value[key]

            if key in data:
                old_value = data[key]
                if isinstance(old_value, dict):
                    data[key] = [old_value, value]
                elif isinstance(old_value, list):
                    data[key].append(value)
            elif key in self.LIST_KEYS:
                data[key] = [value]
            elif key in self.SIMPLE_KEYS:
                data[key] = value
            elif key in self.IGNORE_KEYS:
                continue
            else:
                logger.info(f"Ignoring key {key} from {parentElement.tag}")
                self.IGNORE_KEYS.add(key)

        # Filling defaults
        if parentElement.tag == "MeshHeading" and "QualifierName" not in data:
            data["QualifierName"] = ""
        elif parentElement.tag == "Author":
            if "ForeName" not in data:
                data["ForeName"] = ""
            if "Initials" not in data:
                data["Initials"] = ""
            if "LastName" not in data:
                data["LastName"] = ""
            if "CollectiveName" not in data:
                data["CollectiveName"] = ""
        elif parentElement.tag == "JournalIssue":
            if "Volume" not in data:
                data["Volume"] = ""
            if "Issue" not in data:
                data["Issue"] = ""
        elif parentElement.tag == "Grant" and "GrantID" not in data:
            data["GrantID"] = ""

        return {parentElement.tag: data}

    def _info(self):
        Date = {
            "Year": datasets.Value("int32"),
            "Month": datasets.Value("int32"),
            "Day": datasets.Value("int32"),
        }

        MeshHeading = {"DescriptorName": datasets.Value("string"), "QualifierName": datasets.Value("string")}

        MedlineJournalInfo = {
            "Country": datasets.Value("string"),
            # Too inconsistent
            # 'MedlineTA': datasets.Value('string'),
            # 'NlmUniqueID': datasets.Value('string'),
            # 'ISSNLinking': datasets.Value('string'),
        }
        Chemical = {
            "RegistryNumber": datasets.Value("string"),
            "NameOfSubstance": datasets.Value("string"),
        }
        # Too inconsistent in the data to be used
        # Journal = {
        #         'ISSN': datasets.Value('string'),
        #         'JournalIssue': {
        #             'Volume': datasets.Value('string'),
        #             'Issue': datasets.Value('string'),
        #         },
        #         # 'PubDate': Date,
        #         'Title': datasets.Value('string'),
        #         'ISOAbbreviation': datasets.Value('string')
        #         }
        Author = {
            "LastName": datasets.Value("string"),
            "ForeName": datasets.Value("string"),
            "Initials": datasets.Value("string"),
            "CollectiveName": datasets.Value("string"),
        }
        Reference = {
            "Citation": datasets.Value("string"),
            "CitationId": datasets.Value("int32"),
        }
        Grant = {
            "GrantID": datasets.Value("string"),
            "Agency": datasets.Value("string"),
            "Country": datasets.Value("string"),
        }
        Article = {
            # 'Journal': Journal,
            "Abstract": {"AbstractText": datasets.Value("string")},
            "ArticleTitle": datasets.Value("string"),
            # Too inconistent
            # 'Pagination': {'MedlinePgn': datasets.Value('string')},
            "AuthorList": {"Author": datasets.Sequence(Author)},
            "Language": datasets.Value("string"),
            "GrantList": {
                "Grant": datasets.Sequence(Grant),
            },
            "PublicationTypeList": {"PublicationType": datasets.Sequence(datasets.Value("string"))},
        }
        features = datasets.Features(
            {
                "MedlineCitation": {
                    "PMID": datasets.Value("int32"),
                    "DateCompleted": Date,
                    "NumberOfReferences": datasets.Value("int32"),
                    "DateRevised": Date,
                    "Article": Article,
                    "MedlineJournalInfo": MedlineJournalInfo,
                    "ChemicalList": {"Chemical": datasets.Sequence(Chemical)},
                    "CitationSubset": datasets.Value("string"),
                    "MeshHeadingList": {
                        "MeshHeading": datasets.Sequence(MeshHeading),
                    },
                },
                "PubmedData": {
                    "ArticleIdList": datasets.Sequence({"ArticleId": datasets.Sequence(datasets.Value("string"))}),
                    "PublicationStatus": datasets.Value("string"),
                    "History": {"PubMedPubDate": datasets.Sequence(Date)},
                    "ReferenceList": datasets.Sequence(Reference),
                },
            }
        )
        self.fill_keys_from_features(features)
        return datasets.DatasetInfo(
            # This is the description that will appear on the datasets page.
            description=_DESCRIPTION,
            # This defines the different columns of the dataset and their types
            features=features,  # Here we define them above because they are different between the two configurations
            # If there's a common (input, target) tuple from the features,
            # specify them here. They'll be used if as_supervised=True in
            # builder.as_dataset.
            supervised_keys=None,
            # Homepage of the dataset for documentation
            homepage=_HOMEPAGE,
            # License for the dataset if available
            license=_LICENSE,
            # Citation for the dataset
            citation=_CITATION,
        )

    def _split_generators(self, dl_manager):
        """Returns SplitGenerators."""
        dl_dir = dl_manager.download_and_extract(_URLs)
        return [
            datasets.SplitGenerator(
                name=datasets.Split.TRAIN,
                # These kwargs will be passed to _generate_examples
                gen_kwargs={"filenames": dl_dir},
            ),
        ]

    def update_citation(self, article):
        """
        ArticleId and ArticleIdList are already used field name so we rewrite and
        flatten those as {Citation, CitationId}.
        """
        citations = []
        try:
            list_ = article["PubmedData"]["ReferenceList"]
        except Exception:
            return

        for ref in list_:
            if "Reference" not in ref:
                continue
            for re in ref["Reference"]:
                if "Citation" not in re:
                    continue
                citation = re["Citation"]
                if "ArticleIdList" not in re:
                    continue
                for r in re["ArticleIdList"]:
                    if "ArticleId" not in r:
                        continue
                    for rr in r["ArticleId"]:
                        try:
                            citation = {"Citation": citation, "CitationId": int(rr)}
                        except Exception:
                            continue
                        citations.append(citation)
        article["PubmedData"]["ReferenceList"] = citations

    def _generate_examples(self, filenames):
        """ Yields examples. """
        id_ = 0
        for filename in filenames:
            try:
                tree = etree.parse(filename)
                root = tree.getroot()
                xmldict = self.xml_to_dictionnary(root)
            except etree.ParseError:
                logger.warning(f"Ignoring file {filename}, it is malformed")
                continue

            for article in xmldict["PubmedArticleSet"]["PubmedArticle"]:
                self.update_citation(article)
                new_article = default_article()

                try:
                    deepupdate(new_article, article)
                except Exception:
                    logger.warning(f"Ignoring article {article}, it is malformed")
                    continue

                try:
                    _ = self.info.features.encode_example(new_article)
                except Exception as e:
                    logger.warning(f"Ignore example because {e}")
                    continue
                yield id_, new_article
                id_ += 1


import datetime

from django.contrib.auth.models import User
from django.db import connection
from django.views.generic.list_detail import object_list
from django.views.generic.simple import direct_to_template

from emtools.emauth.decorators import require_admin
from emtools.emadmin.models import LogRecord, Schedule

from emtools import utils

OLD_DAYS = 7

@require_admin
def view_log(request):
    return object_list(request, LogRecord.objects.all(),
                       paginate_by=23,
                       template_name='emadmin/log.html',
                       extra_context={'tab': 'log'},
                       template_object_name='log')

@require_admin
def view_status(request):
    return direct_to_template(request, 'emadmin/status.html',
                              extra_context={'tab': 'status',
                                             'schedule_list':
                                                 Schedule.objects.all()})

IGNORED_GROUPS = ['Registered', 'Awaiting Activation', 'Banned']

@require_admin
def view_groups(request):
    db = utils.connect('emforum')
    c = db.cursor()
    c.execute("SELECT gid, title FROM mybb_usergroups")
    gid2name = dict(c.fetchall())
    c.execute("SELECT uid, username, lastactive, usergroup, additionalgroups "
              "FROM mybb_users")
    group_users = {}
    now = datetime.datetime.utcnow()
    for (mybb_uid, mybb_username, lastactive,
         usergroup, additionalgroups) in c.fetchall():
        try:
            user = User.objects.get(profile__mybb_uid=mybb_uid)
        except User.DoesNotExist:
            user = None
        lastactive = datetime.datetime.utcfromtimestamp(lastactive)
        delta = now - lastactive
        gids = [usergroup] + [int(gid) for gid in additionalgroups.split(",")
                              if gid != '']
        for gid in gids:
            group = gid2name.get(gid, "<Group %i>" % gid)
            if group in IGNORED_GROUPS:
                continue
            group_users.setdefault(group, [])
            group_users[group].append({'name': mybb_username,
                                       'user': user,
                                       'lastactive': lastactive,
                                       'days': delta.days,
                                       'cssclass': ('veryold'
                                                    if delta.days > OLD_DAYS
                                                    else '')})
    for users in group_users.values():
        users.sort(lambda a, b: cmp(a['name'].lower(), b['name'].lower()))
    groups = [(name, len(users), users)
              for (name, users) in group_users.items()]
    groups.sort(lambda a, b: cmp(a[0].lower(), b[0].lower()))
    return direct_to_template(request, 'emadmin/groups.html',
                              extra_context={'tab': 'groups',
                                             'group_list': groups})

@require_admin
def view_stats(request):
    conn = utils.connect('emmisc')
    c = conn.cursor()
    c.execute("SELECT table_schema, "
              "       SUM(table_rows) AS rows, "
              "       SUM(data_length + index_length) AS size "
              "FROM information_schema.TABLES "
              "GROUP BY table_schema "
              "ORDER BY size DESC")
    mysql_databases = c.fetchall()
    c.execute("SELECT table_name, "
              "       table_rows AS rows, "
              "       data_length + index_length AS size "
              "FROM information_schema.TABLES "
              "ORDER BY size DESC")
    mysql_tables = c.fetchall()
    c = connection.cursor()
    c.execute("SELECT 'eve', "
              "       (SELECT SUM(n_live_tup) FROM pg_stat_all_tables), "
              "       pg_database_size('eve')")
    postgresql_databases = c.fetchall()
    c.execute("""
SELECT CASE WHEN nspname = 'public'
            THEN relname
            ELSE nspname || '.' || relname
       END AS "relation",
       C.reltuples::numeric AS rows,
       pg_total_relation_size(C.oid) AS "total_size"
  FROM pg_class C
  LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
  WHERE nspname NOT IN ('pg_catalog', 'information_schema')
    AND C.relkind <> 'i'
    AND nspname !~ '^pg_toast'
  ORDER BY pg_total_relation_size(C.oid) DESC
""")
    postgresql_tables = c.fetchall()
    return direct_to_template(request, 'emadmin/stats.html',
                              extra_context={'tab': 'stats',
                                             'mysql_databases': mysql_databases,
                                             'mysql_tables': mysql_tables,
                                             'postgresql_databases': postgresql_databases,
                                             'postgresql_tables': postgresql_tables})


import glob
import os
from musiclang.lang import MusicLang
from musiclang.lang.regexes import remove_voices

class DBMusicLang:

    def __init__(self, database_path):

        self.database_path = database_path
        if not os.path.exists(self.database_path):
            os.makedirs(self.database_path)

    def midifiles(self, source):
        return glob.glob(os.path.join(source, '**/*.mid'), recursive=True)

    def save_to_database(self, source, views):
        import json

        filepath = os.path.join(self.database_path, source.split('/')[-1].replace('.mid', '.msl'))
        with open(filepath, 'w') as f:
            json.dump(views, f)

    def clean_text(self, text):
        return ' '.join(text.split())

    def get_views_from_source(self, source):
        score = MusicLang(source)
        score_not_factorized = MusicLang(source, factorize=False)
        score_half_factorized = MusicLang(source, factorize_full=False)
        chords = remove_voices(str(score))
        res = {
               'chords': self.clean_text(chords),
               'factorized': self.clean_text(str(score)),
               'raw': self.clean_text(str(score_not_factorized)),
               'half_factorized': self.clean_text(str(score_half_factorized))
               }

        return res

    def ingest_one(self, source):
        views = None
        try:
            views = self.get_views_from_source(source)
        except Exception as e:
            print(e)
            print(f'Error with {source}')
        if views is not None:
            self.save_to_database(source, views)

    def ingest_directory(self, source):
        for file in self.midifiles(source):
            self.ingest_one(file)


# -*- coding: utf-8 -*-
"""
Created on Mon Feb  4 17:51:31 2019

@author: Education
"""

from PIL import Image

img = Image.open("IMG20171019190155.jpg")

#print(img.mode)        to show the mode of image

img_gray = img.convert(mode = 'L')      #to convert the mode of a image
img_gray.show()                        #to show the image

img_rotate = img.rotate(90)
img_rotate.show()             #to rotate a iamge

#to crop a image
img_crop = img.crop((40,80,100,204))
img_crop.show()

#to crop a image from center
new_width = 160
new_height = 204

width,height = img.size

left = (width - new_width)/2
top = (height - new_height)/2
right = (width + new_width)/2
bottom = (height + new_height)/2

img_crop1 = img.crop((left,top,right,bottom))
img_crop1.show()

save = img.copy()              #to create copy of image
save.show()

size = (56,45)
img.thumbnail(size)
img.show()


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

def solution(arrows):
    move = [
        (-1, 0),
        (-1, 1),
        (0, 1),
        (1, 1),
        (1, 0),
        (1, -1),
        (0, -1),
        (-1, -1)]
    print(move[6][0])
    edge = []
    vertex = [(0, 0)]
    current = (0, 0)
    room = 0
    for i in arrows:
        current = vertex[-1]
        a, b = current[0] + move[i][0], current[1] + move[i][1]
        if (a, b) in vertex:
            if (current[0], current[1], a, b) in edge or (a, b, current[0], current[1]) in edge:
                continue
            else:
                edge.append((current[0], current[1], a, b))
                vertex.append((a, b))
                room += 1
        else:
            edge.append((current[0], current[1], a, b))
            vertex.append((a, b))
    return room

print(solution(
    [6, 6, 6, 4, 4, 4, 2, 2, 2, 0, 0, 0, 1, 6, 5, 5, 3, 6, 0]
))


import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer

'''
cd appendices/ && python makeindex.py && cd ../
'''

import re,glob

from nltk.corpus import stopwords
stop = list(stopwords.words('english'))
stop.extend('section subsection subsubsection figure table item paragraph begin end caption autoref includegraph  png pdf textwidth endsubfigure subfigure the is this centering label textbf textit emph fig cite citep width height includegraphics sec use ce ch footnote figures shown use used much often within show contain'.split())

files = glob.glob('../*_*.tex')
files.sort()

corpus = []
title = []
for f in files:
    try:
        dir = open(f,'r').read()
        loc = re.findall(r'\\subimport\{([^\}]+)',dir)[0]
        text = open('../%scombigned.tex'%loc,'r').read().lower()
        title.append(re.findall(r'\\chapter\{([^\}]+)',dir)[0])

        text = re.sub(r'[\._\W\s\d]+',' ',re.sub(r'-|([^\\]\%[^\n]+)','',text ))
        corpus.append(text)
    except:None

vectorizer = TfidfVectorizer(analyzer = 'word',stop_words=set(stop))
vectors = vectorizer.fit_transform(corpus)
names = vectorizer.get_feature_names()
data = vectors.todense().tolist()
# Create a dataframe with the results
df = pd.DataFrame(data, columns=names,index=title)

tfidf = '''
\\chapter{Chapter Keywords}
This section uses the Term Frequency Inverse Document Frequency to determine the keywords of each chapter - a techneque which has been described in \\autoref{ch3} and \\cite{frankenstein}. Text size corresponds to the importance of each word.

'''

N = 100;
for i in df.iterrows():
    print('\n\n',i[0])
    tfidf += '\n\n \\section{%s}\n {\\fontfamily{cmtt}\\selectfont \\parbox{\\textwidth}{\n'%i[0]
    rankings = i[1].sort_values(ascending=False)[:N]
    print(rankings)

    for i in rankings.iteritems():
        tfidf += '\\size{%d}{ %s }'%(1+i[1]*100,i[0].upper())

    #tfidf=tfidf[:-2]
    tfidf+='} }'

with open('keywords.tex','w') as f:
    f.write(tfidf)


# -*- coding: utf-8 -*-

"""This module populates the tables of bio2bel_wikipathways."""

import logging
import sys
from typing import Iterable, List, Mapping, Optional, Union

import click
from tqdm import tqdm

import bio2bel_hgnc
from bio2bel.manager.bel_manager import BELManagerMixin
from bio2bel.manager.flask_manager import FlaskMixin
from bio2bel.manager.namespace_manager import BELNamespaceManagerMixin
from compath_utils import CompathManager
from pybel.constants import BIOPROCESS, NAME, PROTEIN
from pybel.manager.models import Namespace, NamespaceEntry
from pybel.struct.graph import BELGraph
from .constants import MODULE_NAME, WIKIPATHWAYS
from .models import Base, Pathway, Protein, protein_pathway
from .parser import parse_gmt_file

__all__ = [
    'Manager',
]

log = logging.getLogger(__name__)
logging.getLogger("urllib3").setLevel(logging.WARNING)

class Manager(CompathManager, BELNamespaceManagerMixin, BELManagerMixin, FlaskMixin):
    """Protein-pathway memberships."""

    module_name = MODULE_NAME
    _base = Base
    edge_model = protein_pathway
    flask_admin_models = [Pathway, Protein]
    namespace_model = pathway_model = Pathway
    pathway_model_identifier_column = Pathway.wikipathways_id
    protein_model = Protein

    identifiers_recommended = 'WikiPathways'
    identifiers_pattern = r'WP\d{1,5}(\_r\d+)?$'
    identifiers_miriam = 'MIR:00000076'
    identifiers_namespace = 'wikipathways'
    identifiers_url = 'http://identifiers.org/wikipathways/'

    """Override views in _make_admin"""

    def _add_admin(self, app, **kwargs):
        from flask_admin import Admin
        from flask_admin.contrib.sqla import ModelView

        class PathwayView(ModelView):
            """Pathway view in Flask-admin."""

            column_searchable_list = (
                Pathway.wikipathways_id,
                Pathway.name
            )

        class ProteinView(ModelView):
            """Protein view in Flask-admin."""

            column_searchable_list = (
                Protein.entrez_id,
                Protein.hgnc_symbol,
                Protein.hgnc_id
            )

        admin = Admin(app, **kwargs)
        admin.add_view(PathwayView(Pathway, self.session))
        admin.add_view(ProteinView(Protein, self.session))
        return admin

    def summarize(self) -> Mapping[str, int]:
        """Summarize the database."""
        return dict(
            pathways=self._count_model(Pathway),
            proteins=self._count_model(Protein),
        )

    def query_pathway_by_name(self, query: str, limit: Optional[int] = None) -> List[Pathway]:
        """Return all pathways having the query in their names.

        :param query: query string
        :param limit: limit result query
        """
        q = self.session.query(Pathway).filter(Pathway.name.contains(query))

        if limit:
            q = q.limit(limit)

        return q.all()

    def get_or_create_pathway(
            self,
            wikipathways_id: str,
            name: Optional[str] = None,
            species: Optional[str] = None,
    ) -> Pathway:
        """Get an pathway from the database or creates it.

        :param wikipathways_id: WikiPathways identifier
        :param name: name of the pathway
        :param species: species in which the pathway was described
        """
        pathway = self.get_pathway_by_id(wikipathways_id)

        if pathway is None:
            pathway = Pathway(
                wikipathways_id=wikipathways_id,
                name=name,
                species=species,
            )
            self.session.add(pathway)

        return pathway

    def get_or_create_protein(self, entrez_id: str, hgnc_symbol: str, hgnc_id: str) -> Protein:
        """Get an pathway from the database or creates it.

        :param entrez_id: entrez identifier
        :param hgnc_symbol: hgnc symbol
        :param hgnc_id: hgnc identifier
        """
        protein = self.get_protein_by_entrez_id(entrez_id)

        if protein is None:
            protein = Protein(
                entrez_id=entrez_id,
                hgnc_symbol=hgnc_symbol,
                hgnc_id=hgnc_id
            )

            self.session.add(protein)

        return protein

    def get_protein_by_entrez_id(self, entrez_id: str) -> Optional[Protein]:
        """Get a protein by its Entrez gene identifier."""
        return self.session.query(Protein).filter(Protein.entrez_id == entrez_id).one_or_none()

    def get_protein_by_hgnc_id(self, hgnc_id: str) -> Optional[Protein]:
        """Get a protein by its HGNC identifier."""
        return self.session.query(Protein).filter(Protein.hgnc_id == hgnc_id).one_or_none()

    def get_protein_by_hgnc_symbol(self, hgnc_symbol: str) -> Optional[Protein]:
        """Get a protein by its HGNC gene symbol."""
        return self.session.query(Protein).filter(Protein.hgnc_symbol == hgnc_symbol).one_or_none()

    """Methods to populate the DB"""

    def populate(self, url: Union[None, str, Iterable[str]] = None):
        """Populate the database.

        :param url: url from a GMT file
        """
        hgnc_manager = bio2bel_hgnc.Manager(engine=self.engine, session=self.session)
        if not hgnc_manager.is_populated():
            hgnc_manager.populate()

        if url is None or isinstance(url, str):
            pathways = parse_gmt_file(url=url)
        elif isinstance(url, Iterable):
            pathways = [
                pathway
                for u in url
                for pathway in parse_gmt_file(url=u)
            ]
        else:
            raise TypeError(f'Invalid type for url: {type(url)} ({url})')

        # Dictionaries to map across identifiers
        entrez_to_hgnc_symbol = hgnc_manager.build_entrez_id_symbol_mapping()
        hgnc_symbol_id = hgnc_manager.build_hgnc_symbol_id_mapping()

        entrez_id_protein = {}
        missing_entrez_ids = set()

        it = tqdm(pathways, desc='Loading WikiPathways')
        for pathway_name, species, wikipathways_id, gene_set in it:
            pathway = self.get_or_create_pathway(
                wikipathways_id=wikipathways_id,
                name=pathway_name.strip(),
                species=species,
            )

            for entrez_id in gene_set:
                if entrez_id in entrez_id_protein:
                    protein = entrez_id_protein[entrez_id]

                else:
                    hgnc_symbol = entrez_to_hgnc_symbol.get(entrez_id)

                    if not hgnc_symbol:
                        it.write(f"({species}) ncbigene:{entrez_id} has no HGNC symbol")
                        missing_entrez_ids.add(entrez_id)
                        continue

                    protein = self.get_or_create_protein(entrez_id, hgnc_symbol, hgnc_symbol_id[hgnc_symbol])
                    entrez_id_protein[entrez_id] = protein

                if pathway not in protein.pathways:
                    protein.pathways.append(pathway)

            self.session.commit()

        if missing_entrez_ids:
            log.warning("Total of {} missing ENTREZ".format(len(missing_entrez_ids)))

    @classmethod
    def _cli_add_populate(cls, main: click.Group) -> click.Group:
        @main.command()
        @click.option('--reset', is_flag=True, help='Nuke database first')
        @click.option('--force', is_flag=True, help='Force overwrite if already populated')
        @click.option('-u', '--url', multiple=True, help='URL of WikiPathways GMT files')
        @click.pass_obj
        def populate(manager: Manager, reset, force, url):
            """Populate the database."""
            if reset:
                click.echo('Deleting the previous instance of the database')
                manager.drop_all()
                click.echo('Creating new models')
                manager.create_all()

            if manager.is_populated() and not force:
                click.echo('Database already populated. Use --force to overwrite')
                sys.exit(0)

            manager.populate(url=url)

        return main

    """Methods to enrich BEL graphs"""

    def to_bel(self) -> BELGraph:
        """Return a new graph corresponding to the pathway.

        Example Usage:

        >>> manager = Manager()
        >>> manager.get_pathway_graph_by_id('WP61') # Notch signaling pathway
        """
        graph = BELGraph(
            name='WikiPathways Associations',
            version='1.0.0',
        )

        wikipathways_namespace = self.upload_bel_namespace()
        graph.namespace_url[wikipathways_namespace.keyword] = wikipathways_namespace.url

        hgnc_manager = bio2bel_hgnc.Manager(engine=self.engine, session=self.session)
        hgnc_namespace = hgnc_manager.upload_bel_namespace()
        graph.namespace_url[hgnc_namespace.keyword] = hgnc_namespace.url

        for pathway in tqdm(self.get_all_pathways(), total=self._count_model(Pathway)):
            for protein in pathway.proteins:
                pathway_bel = pathway.serialize_to_pathway_node()
                protein_bel = protein.serialize_to_protein_node()
                graph.add_part_of(protein_bel, pathway_bel)

        return graph

    def get_pathway_graph_by_id(self, wikipathways_id: str) -> Optional[BELGraph]:
        """Return a new graph corresponding to the pathway.

        :param wikipathways_id: WikiPathways identifier
        :return: A BEL Graph corresponding to the WikiPathways identifier

        Example Usage:

        >>> manager = Manager()
        >>> manager.get_pathway_graph_by_id('WP61') # Notch signaling pathway
        """
        pathway = self.get_pathway_by_id(wikipathways_id)

        if pathway is None:
            return

        graph = BELGraph(
            name=f'{pathway.name} ({pathway.species})',
            version='1.0.0',
        )

        wikipathways_namespace = self.upload_bel_namespace()
        graph.namespace_url[wikipathways_namespace.keyword] = wikipathways_namespace.url

        hgnc_manager = bio2bel_hgnc.Manager(engine=self.engine, session=self.session)
        hgnc_namespace = hgnc_manager.upload_bel_namespace()
        graph.namespace_url[hgnc_namespace.keyword] = hgnc_namespace.url

        pathway_node = pathway.serialize_to_pathway_node()

        for protein in pathway.proteins:
            graph.add_part_of(protein.serialize_to_protein_node(), pathway_node)

        return graph

    def enrich_wikipathways_pathway(self, graph: BELGraph) -> None:
        """Enrich all proteins belonging to WikiPathways pathway nodes in the graph."""
        for node in list(graph):
            if node.function == BIOPROCESS and node.namespace == WIKIPATHWAYS and NAME in node:
                pathway = self.get_pathway_by_name(node.name)
                for protein in pathway.proteins:
                    graph.add_part_of(protein.serialize_to_protein_node(), node)

    def enrich_wikipathways_protein(self, graph: BELGraph) -> None:
        """Enrich all WikiPathways pathways associated with proteins in the graph."""
        for node in list(graph):
            if node.function == PROTEIN and 'namespace' in node and node.namespace == 'HGNC':
                protein = self.get_protein_by_hgnc_symbol(node.name)
                for pathway in protein.pathways:
                    graph.add_part_of(node, pathway.serialize_to_pathway_node())

    def _create_namespace_entry_from_model(self, model: Pathway, namespace: Namespace) -> NamespaceEntry:
        """Create a namespace entry from the model."""
        return NamespaceEntry(encoding='B', name=model.name, identifier=model.wikipathways_id, namespace=namespace)

    @staticmethod
    def _get_identifier(model: Pathway) -> str:
        """Extract the identifier from a pathway mode."""
        return model.wikipathways_id


from os import path

import numpy as np
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score

def load_data():
    '''
    SMSSpamCollection.txt数据集
    第一列是短信的label
    ham：非垃圾短信
    spam：垃圾短信
    \t键后面是短信的正文
    '''
    file_name = path.dirname(__file__) + "/SMSSpamCollection.txt"
    X, y = [], []
    with open(file_name,'r', encoding='UTF-8') as file:
        line = file.readline()
        while line:
            d = line.split("\t")
            X.append(d[1])  #短信正文
            y.append(d[0])  #label
            line = file.readline()

##    print(X[:10])
##    print(y[:10])

    return X, y

def about_train_test_split():
    '''
    X_train, X_test, y_train, y_test =sklearn.model_selection.train_test_split(train_data,train_target,
    test_size=0.4, random_state=0,stratify=y_train)
    参数说明：
    # train_data：所要划分的样本特征集
    # train_target：所要划分的样本结果
    # test_size：样本占比，如果是整数的话就是样本的数量
    # random_state：是随机数的种子。
    # stratify是为了保持split前类的分布。比如有100个数据，80个属于A类，20个属于B类。
    如果train_test_split(... test_size=0.25, stratify = y_all), 那么split之后数据如下：
    training: 75个数据，其中60个属于A类，15个属于B类。
    testing: 25个数据，其中20个属于A类，5个属于B类。

    用了stratify参数，training集和testing集的类的比例是 A：B= 4：1，等同于split前的比例（80：20）。
    通常在这种类分布不平衡的情况下会用到stratify。
    将stratify=X就是按照X中的比例分配
    将stratify=y就是按照y中的比例分配
    '''
    # step 1 调用load_data方法读入数据
    X, y = load_data()
    a = {'ham':0,'spam':1}
    y=[a[s]for s in y]

    # step 2 利用缺省参数调用train_test_split将数据划分为训练集和测试集(X_train, X_test, y_train, y_test)
    X_train_raw, X_test_raw, y_train, y_test=train_test_split(X,y)

    # step 3 创建TfidfVectorizer对象vectorizer, 用训练集的短信文本训练vectorizer，
    #        利用训练好的vectorizer抽取训练集的短信文本和测试集的短信文本的tfidf
    vectorizer=TfidfVectorizer()
    X_train = vectorizer.fit_transform(X_train_raw)
    X_test = vectorizer.transform(X_test_raw)
    print(vectorizer.get_feature_names())
    print("\n抽取训练集的短信文本",X_train)
    print("\n抽取测试集的短信文本", X_test)

    # step 4 创建LogisticRegression对象classifier, 用训练集训练classifier
    #        利用训练好的classifier对测试集进行预测
    #        输出前10个测试样本的预测值、实际值和短信文本
    #        输出分类准确率（利用accuracy_score函数）
    #        返回混淆矩阵（利用confusion_matrix函数）
    classifier = LogisticRegression(solver = 'lbfgs')
    classifier.fit(X_train, y_train)
    y_pred = classifier.predict(X_test)
    for i, prediction in enumerate(y_pred[:10]):
        print('Prediction: %s. Real: %s. Message: %s' % (prediction, y_test[i], X_test_raw[i]))

    print('Accuracy:', accuracy_score(y_test, y_pred))

    return confusion_matrix(y_test, y_pred)

def show_confusion_matrix(c_mat):
    print(c_mat)
    plt.matshow(c_mat)
    plt.title('Confusion matrix')
    plt.colorbar()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.show()

def about_cross_val_score():
    '''
    cross_val_score(estimator, X, y=None, groups=None,
                    scoring=None, cv=’warn’, n_jobs=None, verbose=0, fit_params=None,
                    pre_dispatch=‘2*n_jobs’, error_score=’raise-deprecating’)
    参数：
    estimator： 需要使用交叉验证的算法
    X： 输入样本数据
    y： 样本标签
    groups： 将数据集分割为训练/测试集时使用的样本的组标签（一般用不到）
    scoring： 交叉验证最重要的就是他的验证方式，选择不同的评价方法，会产生不同的评价结果。
    cv： 交叉验证折数或可迭代的次数
    n_jobs： 同时工作的cpu个数（-1代表全部）
    verbose： 详细程度
    fit_params： 传递给估计器（验证算法）的拟合方法的参数
    pre_dispatch： 控制并行执行期间调度的作业数量。
    error_score： 如果在估计器拟合中发生错误，要分配给该分数的值（一般不需要指定）
    '''
    X, y = load_data()
    a = {'ham':0,'spam':1}
    y = [ a[s] for s in y]  #将label转换为0和1
    vectorizer = TfidfVectorizer()
    X = vectorizer.fit_transform(X)
    classifier = LogisticRegression(solver = 'lbfgs')

    # step 1 利用5折交叉验证对classifier进行训练，输出accuracy
    scores = cross_val_score(classifier, X, y, cv = 5, scoring = 'accuracy')
    print('Accuracy:', np.mean(scores), scores)

    # step 2 利用5折交叉验证对classifier进行训练，输出precision
    precision = cross_val_score(classifier, X, y, cv=5, scoring='precision')
    print('Precision:', np.mean(precision), precision)

    # step 3 利用5折交叉验证对classifier进行训练，输出recall
    recall = cross_val_score(classifier, X, y, cv=5, scoring='recall')
    print('Recall:', np.mean(recall), recall)

    # step 4 利用5折交叉验证对classifier进行训练，输出f1
    f1 = cross_val_score(classifier, X, y, cv=5, scoring='f1')
    print('F1:', np.mean(f1), f1)

from sklearn.metrics import precision_recall_curve
from sklearn.metrics import average_precision_score

def about_P_R_curve():
    '''
    sklearn.metrics.precision_recall_curve(y_true, probas_pred, *, pos_label=None, sample_weight=None)
    Compute precision-recall pairs for different probability thresholds

    Note: this implementation is restricted to the binary classification task.
    The precision is the ratio tp / (tp + fp) where tp is the number of true positives and fp the number of false positives. The precision is intuitively the ability of the classifier not to label as positive a sample that is negative.
    The recall is the ratio tp / (tp + fn) where tp is the number of true positives and fn the number of false negatives. The recall is intuitively the ability of the classifier to find all the positive samples.
    The last precision and recall values are 1. and 0. respectively and do not have a corresponding threshold. This ensures that the graph starts on the y axis.

    Parameters
    y_true array, shape = [n_samples]
    True binary labels. If labels are not either {-1, 1} or {0, 1}, then pos_label should be explicitly given.

    probas_pred array, shape = [n_samples]
    Estimated probabilities or decision function.

    pos_label int or str, default=None
    The label of the positive class. When pos_label=None, if y_true is in {-1, 1} or {0, 1}, pos_label is set to 1, otherwise an error will be raised.

    sample_weight array-like of shape (n_samples,), default=None
    Sample weights.

    Returns
    precision array, shape = [n_thresholds + 1]
    Precision values such that element i is the precision of predictions with score >= thresholds[i] and the last element is 1.

    recall array, shape = [n_thresholds + 1]
    Decreasing recall values such that element i is the recall of predictions with score >= thresholds[i] and the last element is 0.

    thresholds array, shape = [n_thresholds <= len(np.unique(probas_pred))]
    Increasing thresholds on the decision function used to compute precision and recall.
    '''
    X, y = load_data()
    a = {'ham':0,'spam':1}
    y = [ a[s] for s in y]  #将label转换为0和1
    X_train_raw, X_test_raw, y_train, y_test = train_test_split(X, y)

    vectorizer = TfidfVectorizer()
    X_train = vectorizer.fit_transform(X_train_raw)
    X_test = vectorizer.transform(X_test_raw)

    classifier = LogisticRegression(solver = 'lbfgs')
    classifier.fit(X_train, y_train)

    # step 1 调用predict_proba方法得到测试集的预测概率
    y_pred = classifier.predict_proba(X_test)

    average_precision = average_precision_score(y_test, y_pred[:,1])

    # step 2 调用precision_recall_curve计算P-R曲线上各点的precision和recall
    precision,recall,thresholds=precision_recall_curve(y_test,y_pred[:,1])

    # step 3 调用matplotlib.pyplot的plot方法画P-R曲线
    plt.plot(recall, precision)

    plt.xlabel('Recall')
    plt.ylabel('Precision')
    plt.ylim([0.0, 1.05])
    plt.xlim([0.0, 1.0])
    plt.title('2-class Precision-Recall curve: AP={0:0.2f}'.format(average_precision))
    plt.show()

from sklearn.metrics import roc_curve, auc
def about_ROC_curve():
    '''
    sklearn.metrics.roc_curve(y_true, y_score, pos_label=None, sample_weight=None, drop_intermediate=True)

    主要参数：
    y_true：真实的样本标签，默认为{0，1}或者{-1，1}。如果要设置为其它值，则 pos_label 参数要设置为特定值。
            例如要令样本标签为{1，2}，其中2表示正样本，则pos_label=2
    y_score：对每个样本的预测结果。
    pos_label：正样本的标签

    返回值：
    fpr：False positive rate
    tpr：True positive rate (Recall)
    thresholds
    '''
    X, y = load_data()
    a = {'ham':0,'spam':1}
    y = [ a[s] for s in y]

    X_train_raw, X_test_raw, y_train, y_test = train_test_split(X, y)

    # step 1 创建TfidfVectorizer对象vectorizer, 用训练集的短信文本训练vectorizer，
    #        利用训练好的vectorizer抽取训练集的短信文本和测试集的短信文本的tfidf
    vectorizer=TfidfVectorizer()
    X_train = vectorizer.fit_transform(X_train_raw)
    X_test = vectorizer.transform(X_test_raw)
    print(vectorizer.get_feature_names())
    print("\n抽取训练集的短信文本",X_train)
    print("\n抽取测试集的短信文本", X_test)

    # step 2 创建LogisticRegression对象classifier, 用训练集训练classifier
    #        利用训练好的classifier对测试集进行预测,得到预测概率值
    classifier = LogisticRegression(solver = 'lbfgs')
    classifier.fit(X_train, y_train)
    y_pred = classifier.predict_proba(X_test)

    # step 3 根据真实标签和预测概率值调用roc_curve计算false_positive_rate、recall和thresholds
    #        调用auc计算ROC曲线下方的面积大小roc_auc
    false_positive_rate,recall,thresholds=roc_curve(y_test,y_pred[:,1])
    roc_auc=auc(false_positive_rate,recall)
    # step 4 画ROC曲线
    plt.plot(false_positive_rate, recall, 'b', label='AUC = %0.2f' %roc_auc)

    plt.title('Receiver Operating Characteristic')
    plt.legend(loc='lower right')
    plt.plot([0, 1], [0, 1], 'r--')
    plt.xlim([0.0, 1.0])
    plt.ylim([0.0, 1.0])
    plt.ylabel('Recall')
    plt.xlabel('Fall-out')
    plt.show()

if __name__=="__main__":
    c_m = about_train_test_split()
    show_confusion_matrix(c_m)
    about_cross_val_score()
    about_P_R_curve()
    about_ROC_curve()


from django.shortcuts import render
from django.views.generic import CreateView, DeleteView, ListView, UpdateView, DetailView
from lugati.lugati_points_of_sale.models import SalesPoint, City
from lugati.lugati_points_of_sale.forms import CityForm
from django.contrib.sites.models import get_current_site
import math
from django.http import HttpResponse
import json
from django.views.decorators.csrf import csrf_exempt
from django.core.urlresolvers import resolve

import logging
logger = logging.getLogger(__name__)

def get_points_of_sale_control_panel(request):
    return render(request, 'lugati_admin/points_of_sale/points_of_sale_control_panel.html')

def get_points_of_sale_tree(request):
    dt = []
    sales_points = SalesPoint.objects.all()
    for sales_point in sales_points:

        cur_node = {
            'label': sales_point.name,
            'uid': sales_point.id,
            'data': {
                'definition': sales_point.name
            }
        }

        dt.append(cur_node)

    return HttpResponse(json.dumps(dt))

class UpdateSalesPoint(UpdateView):
    model = SalesPoint
    #template_name = 'lugati_admin/points_of_sale/create_sales_point.html'
    template_name = 'lugati_admin/points_of_sale/update_sales_point_new.html'
    success_url = '/lugati_admin/points_of_sale/'

#cities
def get_cities_tree_ajax(request):
    cur_site = get_current_site(request)

    def get_cities_tree(region=None, level=0):
        dt = []
        cities = City.objects.filter(site=cur_site).filter(region=region).order_by('is_region', 'name')
        for city in cities:
            cur_node = {
                'label': city.name,
                'uid': city.id,
                'data': {
                    'definition': city.name
                }
            }
            children = City.objects.filter(region = city)
            if children.exists():
                cur_node['children'] = get_cities_tree(region=city, level=level+1)
            dt.append(cur_node)
        return dt

    res_dt = get_cities_tree()
    return HttpResponse(json.dumps(res_dt))

def list_cities(request):
    return render(request, 'lugati_admin/cities/list_cities_new.html')

class CreateCity(CreateView):
    model = City
    template_name = 'lugati_admin/cities/create_city.html'
    success_url = '/lugati_admin/points_of_sale/cities/'

    form_class = CityForm

    def get_initial(self):
        res = {}

        match = resolve(self.request.path)
        if match.url_name == 'create_region':
            res['is_region'] = True
        else:
            res['is_region'] = False
        cur_site = get_current_site(self.request)
        res['site'] = cur_site
        return res
    def form_invalid(self, form):
        if self.request.is_ajax():
            form_errors = {}
            for k in form.errors:
                form_errors[k] = form.errors[k][0]
            res_dt = {
                'error': True,
                'form_errors': form_errors
            }
            return HttpResponse(json.dumps(res_dt))
    def form_valid(self, form):
        self.object = form.save()

        if self.request.is_ajax():
            res_dt = {
                'error': False
            }
            return HttpResponse(json.dumps(res_dt))

class UpdateCity(UpdateView):
    model = City
    template_name = 'lugati_admin/cities/update_city.html'
    success_url = '/lugati_admin/points_of_sale/cities/'

    def form_invalid(self, form):
        if self.request.is_ajax():
            res_dt = {
                'error': True
            }
            return HttpResponse(json.dumps(res_dt))
    def form_valid(self, form):
        self.object = form.save()

        if self.request.is_ajax():
            res_dt = {
                'error': False
            }
            return HttpResponse(json.dumps(res_dt))

class DeleteCity(DeleteView):
    model = City
#~


import acm
import ael
import math

target_delta = 0.00005

def getPrice(object, **rest):
    var_swap = object.Instrument()

    estimate1, estimate2 = get_solver_estimates(var_swap)
    cutoff_strike = secant(find_strike, estimate1, estimate2, var_swap)

    return cutoff_strike

def rational_approximation(t):
    # Abramowitz and Stegun formula 26.2.23.
    # The absolute value of the error should be less than 4.5 e-4.
    c = [2.515517, 0.802853, 0.010328]
    d = [1.432788, 0.189269, 0.001308]
    numerator = (c[2]*t + c[1])*t + c[0]
    denominator = ((d[2]*t + d[1])*t + d[0])*t + 1.0
    return t - numerator / denominator

def normal_CDF_inverse(p):
    assert p > 0.0 and p < 1
    if p < 0.5:
        # F^-1(p) = - G^-1(p)
        return -rational_approximation(math.sqrt(-2.0*math.log(p)))
    else:
        return rational_approximation(math.sqrt(-2.0*math.log(1.0-p)))

def get_underlying_price(ins, calculationSpace):
    calculationSpace.Clear()
    calculation = ins.Calculation()
    return calculation.UnderlyingPrice(calculationSpace).Number()

def get_forward_price(ins, fwd_date, calculationSpace):
    calculationSpace.Clear()
    calculation = ins.Calculation()
    return calculation.ForwardPrice(calculationSpace, fwd_date).Number()

def calculate_strike(fwd_price, vol, time_to_expiry, spot_price, discount_factor, deltacutoff):
    val = fwd_price * math.exp(0.5 * vol**2 * time_to_expiry - \
           normal_CDF_inverse(deltacutoff * spot_price / (fwd_price * discount_factor)) * \
           vol * math.sqrt(time_to_expiry))
    return val

def get_discountfactor(ins, end_date):
    yield_curve = ins.MappedDiscountLink().Link().YieldCurveComponent()
    return yield_curve.IrCurveInformation().Rate(acm.Time().DateToday(), end_date, 'Discount', 'Act/365', 'Discount', None, 0)

def get_distinct_elements(input):
    ''' Return the last two distinct elements from a list.
        If all elements are the same then increment the one element.
    '''
    distinct_items = sorted(list(set(input)))

    if len(distinct_items) > 1:
        return distinct_items[len(distinct_items)-1], distinct_items[len(distinct_items)-2]
    else:
        return distinct_items[0], distinct_items[0] + 100

def get_solver_estimates(var_swap):
    calculationSpace = acm.Calculations().CreateStandardCalculationsSpaceCollection()
    option = acm.FInstrument['OptionDefault']

    expiry_date = var_swap.ExpiryDate()

    option.Simulate()

    option.Underlying(var_swap.Underlying())
    option.ExpiryDate(expiry_date)
    option.Currency(var_swap.Currency())
    option.StrikeCurrency(var_swap.Currency())
    option.IsCallOption(True)

    vol_surface = option.MappedVolatilityLink().Link().VolatilityStructure()
    vol_information = vol_surface.VolatilityInformation(acm.Time().DateToday(), 0.00001)

    fwd_price = get_forward_price(option.Underlying(), expiry_date, calculationSpace)
    spot_price = get_underlying_price(option, calculationSpace)
    time_to_expiry = acm.Time().DateDifference(expiry_date, acm.Time().DateToday()) / 365.0
    df = get_discountfactor(option, expiry_date)

    option.Unsimulate()

    K = fwd_price
    strike_estimates = []
    for i in range(5):
        vol = vol_information.Value(expiry_date, expiry_date, K, True, False)
        K = calculate_strike(fwd_price, vol, time_to_expiry, spot_price, df, target_delta)
        strike_estimates.append(K)

    estimate1, estimate2 = get_distinct_elements(strike_estimates)

    return estimate1, estimate2

def secant(func, oldx, x, var_swap, TOL=1e-7):
    calculationSpace = acm.Calculations().CreateStandardCalculationsSpaceCollection()
    option = acm.FInstrument['OptionDefault']
    option.Simulate()
    option.Underlying(var_swap.Underlying())
    option.ExpiryDate(var_swap.ExpiryDate())
    option.IsCallOption(True)
    option.StrikeCurrency(var_swap.Currency())
    option.Currency(var_swap.Currency())

    oldf, f = func(oldx, option, calculationSpace), func(x, option, calculationSpace)
    if (abs(f) > abs(oldf)):        # swap so that f(x) is closer to 0
        oldx, x = x, oldx
        oldf, f = f, oldf
    count = 0
    while True:
        if (float(f-oldf) == 0):
            option.Unsimulate()
            return 'Optimization did not converge'
        dx = f * (x - oldx) / float(f - oldf)
        if abs(dx) < TOL * (1 + abs(x)):
            option.Unsimulate()
            return str("%.10f" % (x-dx))
        else:
            if count >= 500:
                option.Unsimulate()
                return 'Optimization did not converge'
        oldx, x = x, x - dx
        oldf, f = f, func(x, option, calculationSpace)
        count = count + 1

def find_strike(strike, ins_option, calculationSpace):
    ins_option.StrikePrice(strike)
    calculationSpace.Clear()
    calculation = ins_option.Calculation()
    delta = calculation.PriceDelta(calculationSpace)

    return delta.Number() - target_delta


# class Solution:
#     def nextPermutation(self, nums: List[int]) -> None:
#         """
#         Do not return anything, modify nums in-place instead.
#         """
#         output = []
#         for i in reversed(range(len(nums))):
#             if nums[i] > nums[i - 1]:
#                 nums[i], nums[i - 1] = nums[i - 1], nums[i]
#                 return nums
#             else:
#                 output.append(nums[i])
#         return output

# input: list of integers -> output: list of integers permuted to be a little greater, or sorted in ascending order.

# this boils down to figuring out if an array is monotonically decreasing, and trying to get it to monotonically decrease.
# We can probably check from the back for monotonically increasing actually.
# all the while we can append values?

# Solution:
# Find the next lexicographic permutation of the given list of numbers

# Approach 1: Brute Force
# Find every possible permutation of list formed by the elements of the given array and find out the permutation which is just larger than the given one.  This will be a very naive approach, since it requires us to find out every possible permutation which will take really long time.  This approach isn't really acceptable because of the complexity of the implementation and the time complexity.
# Time: O(N!) since the total number of possible permutations is n!
# Space: O(N) sicne an array will be used to store all the permutations.

# Approach 2: Single Pass Approach
# Observe that, for any given sequence in descending order, no next larger permutation is possible.
# Find the first pair of two successive numbers a[i] and a[i - 1] which satisfy a[i] > a[i - 1].  No rearrangement to the right of a[i - 1] can create a larger permutation since that subarray consists of numbers in descending order.
# what kind of rearrangement will produce the next larger number?  Replace the number a[i - 1] with the number just larger than itself among the numbers lying to its right section.
# Swap numbers a[i - 1] and a[j].
# Time complexity: O(n) in the worst case, only two scans of the whole array are needed
# Space complexity: O(1) since no extra space is used, in place replacements are done.

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        i = j = len(nums) - 1
        while i > 0 and nums[i - 1] >= nums[i]:
            i -= 1
        if i == 0:  # nums are in descending order
            nums.reverse()
            return
        k = i - 1  # find the last 'ascending' position
        while nums[j] <= nums[k]:
            j -= 1
        nums[k], nums[j] = nums[j], nums[k]
        l, r = k + 1, len(nums) - 1  # reverse the second part
        while l < r:
            nums[l], nums[r] = nums[r], nums[l]
            l += 1
            r -= 1


import numpy as np
import random
from math import sqrt, pi, exp

def gaussian_prob(obs, mu, sig):
    num = (obs - mu)**2
    denum = 2*sig**2
    norm = 1 / sqrt(2*pi*sig**2)
    return norm * exp(-num/denum)

class GNB(object):

	def __init__(self):
		self.possible_labels = ['left', 'keep', 'right']

	def train(self, data, labels):
		"""
        X is an array of training data, each entry of which is a
        length 4 array which represents a snapshot of a vehicle's
        s, d, s_dot, and d_dot coordinates.

        Y is an array of labels, each of which is either 'left', 'keep',
        or 'right'. These labels indicate what maneuver the vehicle was
        engaged in during the corresponding training data snapshot.
    """

	 # Prepare totals_by_label array
		num_vars = 4

		totals_by_label = {
            "left" : [],
            "keep" : [],
            "right": [],
		}

		# Create empty array for each label & variable
		for label in self.possible_labels:
			for i in range(num_vars):
				totals_by_label[label].append([])

		# Fill array with values in data
		for x, label in zip(data, labels):
			for i,val in enumerate(x):
				totals_by_label[label][i].append(val)

		means = []
		stds = []
		for label in self.possible_labels:
			means.append([])
			stds.append([])
			for list in totals_by_label[label]:
				std = np.std(list)
				stds[-1].append(std)

				mean = np.mean(list)
				means[-1].append(mean)

		self._means = means
		self._stds = stds

	def _predict(self, obs):
		"""
		Private method used to assign a probability to each class.
		"""

		probs = []
		for (means, stds, lab) in zip(self._means, self._stds, self.possible_labels):
			product = 1
			for mu, sig, o in zip(means, stds, obs):
				likelihood = gaussian_prob(o, mu, sig)
				product *= likelihood
			probs.append(product)
		t = sum(probs)
		return [p/t for p in probs]

	def predict(self, observation):
		probs = self._predict(observation)
		idx = 0
		best_p = 0
		for i, p in enumerate(probs):
			if p > best_p:
				best_p = p
				idx = i
		names = ['left','keep','right']
		return names[idx]

Preparation/Naive Bayes - Python/classifier.py


import click
import rubrik_oracle_module as rbk

@click.command()
@click.argument('host_cluster_db')
@click.option('--force', '-f', is_flag=True, help='Force unmount')
def cli(host_cluster_db, force):
    """
    This will unmount a Rubrik live mount using the database name and the live mount host.

\b
    Args:
        host_cluster_db (str): The hostname the database is running on : The database name
        force (bool): Force the unmount
\b
    Returns:
        unmount_info (dict): Status of the unmount request.
    """
    rubrik = rbk.connect_rubrik()
    cluster_info = rbk.get_cluster_info(rubrik)
    timezone = cluster_info['timezone']['timezone']
    print("Connected to cluster: {}, version: {}, Timezone: {}.".format(cluster_info['name'], cluster_info['version'], timezone))
    host_cluster_db = host_cluster_db.split(":")
    live_mount_ids = rbk.get_oracle_live_mount_id(rubrik, cluster_info['id'], host_cluster_db[1], host_cluster_db[0])
    if not live_mount_ids:
        raise RubrikOracleUnmountError("No live mounts found for {} live mounted on {}. ".format(host_cluster_db[1], host_cluster_db[0]))
    else:
        unmount_info = []
        for live_mount_id in live_mount_ids:
            unmount_response = rbk.live_mount_delete(rubrik, live_mount_id, force)
            print("Live mount id: {} Unmount status: {}.".format(live_mount_id, unmount_response['status']))
            unmount_info.append(unmount_response)
        return unmount_info

class RubrikOracleUnmountError(rbk.NoTraceBackWithLineNumber):
    """
        Renames object so error is named with calling script
    """
    pass

if __name__ == "__main__":
    cli()


# ----------------------------------------------------------------------------------------------------------- #
#
# Program developped for simple S(E)IR model of corona virus infections in Denmark.
#
# Data from:
#
#   Developed by: Troels C. Petersen (NBI, petersen@nbi.dk), Mathias Heltberg, and Christian Michelsen
#   First version:  24. Mar. 2020 by Troels Petersen
#   Latest version: 15. Sep. 2020
#
# ----------------------------------------------------------------------------------------------------------- #

from __future__ import division, print_function
from numba import jit
import importlib
import Config
from ExternalFunctions import nice_string_output, add_text_to_ax
from ExternalFunctions import UnbinnedLH, Chi2Regression

import sys
import numpy as np
import matplotlib.pyplot as plt
# import seaborn as sns
from iminuit import Minuit
from scipy import stats
import pandas as pd
from scipy import interpolate

sys.path.append('External_Functions')

# ----------------------------------------------------------------------------------------------------------- #
plt.close('all')

Config = importlib.reload(Config)
case = Config.load_case

# 61000 tested with 2 days between
# 21000 Tested positive
# 10000 from week 19 and forward

# Antal tested 22576, med 10053 efter uge 19 (hvor tracing startede) hvoraf 650 positive (6.5%).

# Ialt er der 10000 testede positive efter uge 19.

# Det lader til, at dem, som tester negativ paa dag 4, men positiv paa dag 6 (69 ialt) er "meget normalt",
# idet de udgoer 0.3% af alle testede, hvilket ogsaa er hvad man finder generelt.

# Saa skal man stadig teste paa dag 6?

# Desuden:
# Lokale udbrud bliver maaske "forstoerret" i data, fordi der bliver testet mere (ved mobilt telt).

# ----------------------------------------------------------------------------------------------------------- #
# Load specific case from config file

# # Municipalities considered Copenhagen area (from a Covid-19 outbreak point of view):
# area_cph = ["Copenhagen", "Frederiksberg", "Gentofte", "Dragør", "Vallensbæk", "Ballerup", "Gladsaxe", "Herlev", "Hvidovre", "Lyngby-Taarbæk", "Rødovre", "Brøndby", "Glostrup", "Høje-Taastrup", "Tårnby", "Ishøj", "Albertslund"]

# # Municipalities considered Aarhus area (from a Covid-19 outbreak point of view):
# area_aarhus = ["Aarhus"]

# ----------------------------------------------------------------- #
# The data:
# ----------------------------------------------------------------- #

data_posi = pd.read_csv("Municipality_cases_time_series.csv",
                        sep=';', thousands='.', index_col=0)
data_test = pd.read_csv(
    "Municipality_tested_persons_time_series.csv", sep=';', thousands='.', index_col=0)

print(data_test.head(10))
print("...")
print(data_test.tail(10))

# Load Municipalities
Nposi = data_posi.loc["2020-03-01":"2020-09-24"][case['Municipalities']
                                                 ].values.sum(axis=1)
Ntest = data_test.loc["2020-03-01":"2020-09-24"][case['Municipalities']
                                                 ].values.sum(axis=1)
eNtest = np.sqrt(Ntest)
# # Two 1D arrays:
# Nposi_aarhus = data_posi.loc["2020-03-01":"2020-09-16"][area_aarhus].values.sum(axis=1)
# Ntest_aarhus = data_test.loc["2020-03-01":"2020-09-16"][area_aarhus].values.sum(axis=1)
# eNtest_aarhus = np.sqrt(Ntest_aarhus)

# Nposi_cph = data_posi.loc["2020-03-01":"2020-09-16"][area_cph].values.sum(axis=1)
# Ntest_cph = data_test.loc["2020-03-01":"2020-09-16"][area_cph].values.sum(axis=1)
# eNtest_cph = np.sqrt(Ntest_cph)

# # All of Denmark
# Nposi_all = data_posi.loc["2020-03-01":"2020-09-16"].sum(axis=1)
# Ntest_all = data_test.loc["2020-03-01":"2020-09-16"].sum(axis=1)
# eNtest_all = np.sqrt(Ntest_all)

# Make a list of days with the proper length:
print("Number of days for which there is data:", len(data_posi))

# Get the number of positive tests and uncertainty, assume a fixed number of daily tests (=3000):
dayLockdown_aarhus = case['dayLockdown']
# nAveDailyTests_aarhus = case['scale_test']
fPos = Nposi / Ntest
nPos_aarhus = case['scale_test'] * fPos
enPos_aarhus = case['scale_test'] * \
    np.sqrt(fPos*(1.0-fPos)/Ntest + case['SystError']**2)
day = np.arange(0, len(nPos_aarhus))
# dayLockdown_cph = 192   # Unknown!
# nAveDailyTests_cph = 12000.0
# fPos_cph = Nposi_cph / Ntest_cph
# nPos_cph  = nAveDailyTests_cph * fPos_cph
# enPos_cph = nAveDailyTests_cph * np.sqrt(fPos_cph*(1.0-fPos_cph)/Ntest_cph + SystError**2)

Plot_StartDay, Plot_EndDay = case['Plot_range']
Fit_StartDay, Fit_EndDay = case['Fit_range']
save_plots = case['save_plots']
if False:
    # Number of tests in Aarhus and Cph as a function of time:
    fig_Ntests, ax_Ntests = plt.subplots(figsize=(12, 7))
    ax_Ntests.set(xlabel="Day (1st of March is day 0)",
                  ylabel="Tests / day", title=f"Test per day for {case['Name']}")
    ax_Ntests.errorbar(day[Plot_StartDay:Plot_EndDay], Ntest[Plot_StartDay:Plot_EndDay],
                       yerr=eNtest[Plot_StartDay:Plot_EndDay], fmt='.', linewidth=2, label=f"N tests in {case['Name']}", color='red')
    # ax_Ntests.errorbar(day[Plot_StartDay:Plot_EndDay], Ntest_cph[Plot_StartDay:Plot_EndDay], yerr=eNtest_cph[Plot_StartDay:Plot_EndDay], fmt='.', linewidth=2, label='N tests in CphArea', color='blue')
    ax_Ntests.legend(loc=(0.05, 0.75), fontsize=16)
    d_N = {
        'Mean daily tests:': f"{int(np.mean(Ntest[Fit_StartDay:Fit_EndDay]))}"}
    add_text_to_ax(0.05, 0.65, nice_string_output(
        d_N, decimals=0), ax=ax_Ntests, fontsize=12)
    plt.tight_layout()
    plt.show(block=False)
    if (save_plots):
        plt.savefig(f"figures/{case['Name']}_NDailyTests.pdf")

# ----------------------------------------------------------------- #
# SIR model with time variation in beta:
# ----------------------------------------------------------------- #

# SIR Model, including modelling varying beta:
def func_SIRmodel(x, dayLockdown, nI0, beta0, beta1, gamma):

    # These numbers are the current status for each type of case, NOT cumulative.
    NdaysModelExtendsBeyondData = 5
    NdaysModel = len(nPos_aarhus) + NdaysModelExtendsBeyondData
    mS = np.zeros(NdaysModel)   # Susceptible
    mI = np.zeros(NdaysModel)   # Infected
    mR = np.zeros(NdaysModel)   # Recovered
    mTot = np.zeros(NdaysModel)   # Overall number (for check)

    # Initial numbers:
    dayN = Fit_StartDay
    mS[dayN] = 5800000-nI0
    mI[dayN] = nI0
    mR[dayN] = 0
    mTot[dayN] = mS[dayN]+mI[dayN]     # There are no Recovered, yet!

    # Model loop:
    # -----------------
    while (dayN < len(nPos_aarhus)-1 and mI[dayN] > 0):
        dayN += 1
        if (dayN < dayLockdown):     # Could potentially be a fitting parameter!
            beta = beta0
#        elif (dayN < 25) :
#            beta = beta1
        else:
            beta = beta1
            # beta = max(beta0 - dbeta*(dayN-dayLockdown), beta_inf)

        dI = beta*mI[dayN-1] * (mS[dayN-1] / mTot[dayN-1])
        dR = gamma*mI[dayN-1]
        mS[dayN] = mS[dayN-1] - dI
        mI[dayN] = mI[dayN-1] + dI - dR
        mR[dayN] = mR[dayN-1] + dR
        mTot[dayN] = mS[dayN] + mI[dayN] + \
            mR[dayN]       # Should remain constant!

    return mI[x]

func_SIRmodel_vec = np.vectorize(func_SIRmodel)

# ----------------------------------------------------------------- #
# SEIR model with time variation in beta:
# ----------------------------------------------------------------- #

# SEIR model, including modelling of time delays and varying beta:
@jit
def func_SEIRmodel(x, dayLockdown, nI0, beta0, beta1, lambdaE, lambdaI):

    # Initial numbers:
    N_tot = 5800000
    S = N_tot - nI0

    # The initial number of exposed and infected are scaled to match beta0. Factors in front are ad hoc!
    Norm = np.exp(0.8*lambdaE * beta0) + np.exp(0.7*lambdaE * beta0) + np.exp(0.6*lambdaE * beta0) + np.exp(0.5*lambdaE * beta0) +\
        np.exp(0.4*lambdaI * beta0) + np.exp(0.3*lambdaI * beta0) + \
        np.exp(0.2*lambdaI * beta0) + np.exp(0.1*lambdaI * beta0)
    E1 = nI0 * np.exp(0.8*lambdaE * beta0) / Norm
    E2 = nI0 * np.exp(0.7*lambdaE * beta0) / Norm
    E3 = nI0 * np.exp(0.6*lambdaE * beta0) / Norm
    E4 = nI0 * np.exp(0.5*lambdaE * beta0) / Norm
    I1 = nI0 * np.exp(0.4*lambdaI * beta0) / Norm
    I2 = nI0 * np.exp(0.3*lambdaI * beta0) / Norm
    I3 = nI0 * np.exp(0.2*lambdaI * beta0) / Norm
    I4 = nI0 * np.exp(0.1*lambdaI * beta0) / Norm
    """
    E1 = nI0/8
    E2 = nI0/8
    E3 = nI0/8
    E4 = nI0/8
    I1 = nI0/8
    I2 = nI0/8
    I3 = nI0/8
    I4 = nI0/8
    """
    R = 0
    # We define the first day given in the array of days (x) as day 0:
    dayN = Fit_StartDay
    NdaysModelExtendsBeyondData = 5
    NdaysModel = len(nPos_aarhus) + NdaysModelExtendsBeyondData

    # We store the results (time, S, E, I, and R) for each day here:
    SEIR_result = np.zeros((NdaysModel, 5))
    SEIR_result[dayN] = [dayN, S, E1+E2+E3+E4, I1+I2+I3+I4, R]

    # Numerical settings:
    nStepsPerDay = 24           # We simulated in time steps of 1 hour
    dt = 1.0 / nStepsPerDay     # Time step length in days

    # Model loop:
    # -----------------
    while (dayN < NdaysModel-1 and I1 >= 0):

        dayN += 1
        if (dayN < dayLockdown):
            beta = beta0
        else:
            beta = beta1
            # beta = max(beta0 - dbeta*(dayN-dayLockdown), beta_inf)   # Minimum value of beta (at time infinity)

        # Now divide the daily procedure into time steps:
        for _ in range(nStepsPerDay):
            dS = -beta*(I1+I2+I3+I4) * (S / N_tot)
            dE1 = -dS - lambdaE * E1
            dE2 = lambdaE * E1 - lambdaE * E2
            dE3 = lambdaE * E2 - lambdaE * E3
            dE4 = lambdaE * E3 - lambdaE * E4
            dI1 = lambdaE * E4 - lambdaI * I1
            dI2 = lambdaI * I1 - lambdaI * I2
            dI3 = lambdaI * I2 - lambdaI * I3
            dI4 = lambdaI * I3 - lambdaI * I4
            dR = lambdaI * I4

            S += dt * dS
            E1 += dt * dE1
            E2 += dt * dE2
            E3 += dt * dE3
            E4 += dt * dE4
            I1 += dt * dI1
            I2 += dt * dI2
            I3 += dt * dI3
            I4 += dt * dI4
            R += dt * dR
            Tot = S + E1+E2+E3+E4 + I1+I2+I3+I4 + R

        # Record status of model every day:
        SEIR_result[dayN] = [dayN, S, E1+E2+E3+E4, I1+I2+I3+I4, R]

        # print(dayN, E1+E2+E3+E4, I1+I2+I3+I4, R)

    # Return only the number of infected and only for the relevant days:
    return SEIR_result[x, 3]

func_SEIRmodel_vec = np.vectorize(func_SEIRmodel)

# ----------------------------------------------------------------- #
# Plot/print SIR and/or SEIR model with given parameters (for testing):
# ----------------------------------------------------------------- #

# Plot data (scaled to a fixed number of daily tests):
doSIRModelPlot = case['doSIRModelPlot']
doSEIRModelPlot = case['doSEIRModelPlot']
if (doSIRModelPlot or doSEIRModelPlot):
    fig, ax = plt.subplots(figsize=(12, 7))
    ax.set(xlabel="Day (1st of March is day 0)",
           ylabel="Newly infected / day", title="")
    ax.errorbar(day[Plot_StartDay:Plot_EndDay], nPos_aarhus[Plot_StartDay:Plot_EndDay],
                yerr=enPos_aarhus[Plot_StartDay:Plot_EndDay], fmt='.', linewidth=2, label='Data (scaled)', color='red')

# Plot SIR model on top of data (with fixed parameters):
if (doSIRModelPlot):

    # Model (fixed parameters):
    nI0_plot = 2.0
    beta0_plot = 0.34
    beta1_plot = 0.06
    gamma_plot = 1.0/7.0
    ax.plot(day[Fit_StartDay:Fit_EndDay], func_SIRmodel_vec(day[Fit_StartDay:Fit_EndDay], dayLockdown_aarhus,
                                                            nI0_plot, beta0_plot, beta1_plot, gamma_plot), 'blue', linewidth=1.0, label='SIR Model')

    # Calculate Chi2, Ndof, and Chi2-Probability for this model:
    nPos_est = func_SIRmodel(day[Fit_StartDay:Fit_EndDay],
                             dayLockdown_aarhus, nI0_plot, beta0_plot, beta1_plot, gamma_plot)
    chi2 = np.sum(((nPos_aarhus[Fit_StartDay:Fit_EndDay] -
                    nPos_est) / enPos_aarhus[Fit_StartDay:Fit_EndDay])**2)
    Ndof = len(day[Fit_StartDay:Fit_EndDay]) - 5
    Prob = stats.chi2.sf(chi2, Ndof)
    print(
        f"  SIR Model (fixed for plot):  Prob(Chi2={chi2:6.1f}, Ndof={Ndof:3d}) = {Prob:7.5f}")

# Plot SEIR model on top of data (with fixed parameters):
if (doSEIRModelPlot):

    # Model (fixed parameters):
    nI0_plot = case['nI0_plot']
    beta0_plot = case['beta0_plot']
    beta1_plot = case['beta1_plot']
    lambdaE_plot = case['lambdaE_plot']
    lambdaI_plot = case['lambdaE_plot']
    ax.plot(day[Fit_StartDay:Fit_EndDay], func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay], dayLockdown_aarhus-3,
                                                             nI0_plot, beta0_plot, beta1_plot, lambdaE_plot, lambdaI_plot), 'green', linewidth=1.0, label='SEIR Model')

    # Calculate Chi2, Ndof, and Chi2-Probability for this model:
    nPos_est = func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay], dayLockdown_aarhus,
                                  nI0_plot, beta0_plot, beta1_plot, lambdaE_plot, lambdaI_plot)
    chi2 = np.sum(((nPos_aarhus[Fit_StartDay:Fit_EndDay] -
                    nPos_est) / enPos_aarhus[Fit_StartDay:Fit_EndDay])**2)
    # There are 5 parameters in the fit!
    Ndof = len(day[Fit_StartDay:Fit_EndDay]) - 5
    Prob = stats.chi2.sf(chi2, Ndof)
    print(
        f"  SEIR Model (fixed for plot):  Prob(Chi2={chi2:6.1f}, Ndof={Ndof:3d}) = {Prob:7.5f}")

if (doSIRModelPlot or doSEIRModelPlot):
    ax.legend(loc=(0.05, 0.75), fontsize=16)
    plt.tight_layout()
    plt.show(block=False)
    # if (save_plots) :
    #     plt.savefig("figures/fig_CoronaDataDK_ModelPlot_SEIR2_Sep23.pdf")

# ----------------------------------------------------------------- #
# Fit to data with SIR model:
# ----------------------------------------------------------------- #

# Plot Data:
# ----------
if (case['doFitSIR'] or case['doFitSEIR']):
    print("\n  ------------------------------------  Fitting Stage  --------------------------------------- \n")

    fig_fit, ax_fit = plt.subplots(figsize=(12, 7))
    ax_fit.errorbar(day[Plot_StartDay:Plot_EndDay], nPos_aarhus[Plot_StartDay:Plot_EndDay], yerr=enPos_aarhus[Plot_StartDay:Plot_EndDay],
                    fmt='.', linewidth=2, color="red", label='Newly infected (scaled to 3000 tests)')
    ax_fit.set(xlabel="Day (1st of March is day 0)",
               ylabel="Newly infected / day (scaled)", title="")

# SIR model fit:
# --------------
if (case['doFitSIRinit']):

    endday_OK = Fit_StartDay
    for i_endday in range(Fit_StartDay, Fit_EndDay):
        # Defining Chi2 calculation:
        def ChiSquareCalcSIRinit(dayL, nI0, beta0, beta1, gamma):
            nPos_est = func_SIRmodel(
                day[Fit_StartDay:i_endday], dayL, nI0, beta0, beta1, gamma)
            chi2 = np.sum(
                ((nPos_aarhus[Fit_StartDay:i_endday] - nPos_est) / enPos_aarhus[Fit_StartDay:i_endday])**2)
            return chi2

        minuit_SIRinit = Minuit(ChiSquareCalcSIRinit, pedantic=False, print_level=0, dayL=1000,
                                fix_dayL=True, nI0=0.5, beta0=0.45, beta1=0.06, gamma=0.14, fix_gamma=True)
        minuit_SIRinit.migrad()
        # if (not minuit_SIRinit.fmin.is_valid) :
        # print("  WARNING: The ChiSquare fit DID NOT converge!!! ")

        chi2 = minuit_SIRinit.fmin.fval
        Ndof = len(day[Fit_StartDay:Fit_EndDay]) - len(minuit_SIRinit.args)
        Prob = stats.chi2.sf(chi2, Ndof)
        print(
            f"  SIRinit Model fit:  Day={i_endday:3d}   Prob(Chi2={chi2:6.1f}, Ndof={Ndof:3d}) = {Prob:7.5f}")

        # If model is acceptable (prob > 5%), then save the parameters:
        if (Prob > 0.05):
            dayL_fit, nI0_fit, beta0_fit, beta1_fit, gamma_fit = minuit_SIRinit.args
            endday_OK = i_endday
        else:
            continue

    # Plot the last acceptable fitted model on top of data extending in time:
    ax_fit.plot(day[Fit_StartDay:endday_OK], func_SIRmodel_vec(day[Fit_StartDay:endday_OK], dayL_fit, nI0_fit,
                                                               beta0_fit, beta1_fit, gamma_fit), 'blue', linewidth=1.0, label='Fit with SIR Model - no intervention')
    ax_fit.plot(day[endday_OK-1:endday_OK+2], func_SIRmodel_vec(day[endday_OK-1:endday_OK+2],
                                                                dayL_fit, nI0_fit, beta0_fit, beta1_fit, gamma_fit), 'blue', linewidth=1.0, linestyle="dotted")

Fit_EndDay_delay = case['Fit_EndDay_delay']

# SIR model fit:
# --------------
if (case['doFitSIR']):

    Fit_EndDay = endday_OK + Fit_EndDay_delay

    # Defining Chi2 calculation:
    def ChiSquareCalcSIR(dayL, nI0, beta0, beta1, gamma):
        nPos_est = func_SIRmodel(
            day[Fit_StartDay:Fit_EndDay], dayL, nI0, beta0, beta1, gamma)
        chi2 = np.sum(((nPos_aarhus[Fit_StartDay:Fit_EndDay] -
                        nPos_est) / enPos_aarhus[Fit_StartDay:Fit_EndDay])**2)
        return chi2

    minuit_SIR = Minuit(ChiSquareCalcSIR, pedantic=False, print_level=0,
                        dayL=dayLockdown_aarhus, limit_dayL=[150, 208], nI0=2.0, beta0=0.45, beta1=0.04, gamma=0.14, fix_gamma=True)
    minuit_SIR.migrad()
    if (not minuit_SIR.fmin.is_valid):
        print("  WARNING: The ChiSquare fit DID NOT converge!!! ")

    # Same as minuit_SIR.args
    dayL_fit, nI0_fit, beta0_fit, beta1_fit, gamma_fit = minuit_SIR.values.values()
    edayL_fit, enI0_fit, ebeta0_fit, ebeta1_fit, egamma_fit = minuit_SIR.errors.values()
    if dayL_fit > max(day):
        dayL_fit = 208
    for name in minuit_SIR.parameters:
        print("Fit value (exp): {0} = {1:.5f} +/- {2:.5f}".format(name,
                                                                  minuit_SIR.values[name], minuit_SIR.errors[name]))
    chi2 = minuit_SIR.fmin.fval
    Ndof = len(day[Fit_StartDay:Fit_EndDay]) - len(minuit_SIR.args)
    Prob = stats.chi2.sf(chi2, Ndof)
    print(
        f"  SIR Model fit:  Prob(Chi2={chi2:6.1f}, Ndof={Ndof:3d}) = {Prob:7.5f}")

    # Plot fitted model on top of data extending in time:
    ax_fit.plot(day[Fit_StartDay:Fit_EndDay], func_SIRmodel_vec(day[Fit_StartDay:Fit_EndDay], dayL_fit,
                                                                nI0_fit, beta0_fit, beta1_fit, gamma_fit), 'blue', linewidth=2.0, label='Fit with SIR Model')
    ax_fit.plot(day[Fit_EndDay-1:Fit_EndDay+15], func_SIRmodel_vec(day[Fit_EndDay-1:Fit_EndDay+15],
                                                                   dayL_fit, nI0_fit, beta0_fit, beta1_fit, gamma_fit), 'blue', linewidth=1.0, linestyle="dotted")
    ax_fit.legend(loc=(0.05, 0.80), fontsize=12)
    d_fit = {'SIR-model': "",
             'Prob Chi2': f"{Prob:.5f}",
             r'$\beta_0$     ': f"{minuit_SIR.values['beta0']:.4f}+-{minuit_SIR.errors['beta0']:.4f}",
             r'$\beta_1$    ': f"{minuit_SIR.values['beta1']:.4f}+-{minuit_SIR.errors['beta1']:.4f}",
             "Lockdown": f"{data_posi.iloc[int(dayL_fit)].name}, ({int(dayL_fit)})"}
    add_text_to_ax(0.05, 0.55, nice_string_output(
        d_fit, decimals=0), ax=ax_fit, fontsize=9)

animate = False
# SEIR model fit:
# ---------------
if (case['doFitSEIR']):
    Fit_EndDay = endday_OK + Fit_EndDay_delay

    # Defining Chi2 calculation:
    def ChiSquareCalcSEIR(dayL, nI0, beta0, beta1, lambdaE, lambdaI):
        nPos_est = func_SEIRmodel(
            day[Fit_StartDay:Fit_EndDay], dayL, nI0, beta0, beta1, lambdaE, lambdaI)
        chi2 = np.sum(((nPos_aarhus[Fit_StartDay:Fit_EndDay] -
                        nPos_est) / enPos_aarhus[Fit_StartDay:Fit_EndDay])**2)
        return chi2

    minuit_SEIR = Minuit(ChiSquareCalcSEIR, pedantic=False, print_level=0, dayL=dayLockdown_aarhus-4, fix_dayL=False,
                         limit_dayL=[150, 208], nI0=5.0, beta0=0.40, beta1=0.15, lambdaE=1.0, lambdaI=1.0, fix_lambdaE=True, fix_lambdaI=True)
    minuit_SEIR.migrad()
    if (not minuit_SEIR.fmin.is_valid):
        print("  WARNING: The ChiSquare fit DID NOT converge!!! ")

    dayL_fit, nI0_fit, beta0_fit, beta1_fit, lambdaE_fit, lambdaI_fit = minuit_SEIR.args
    dayL_fiterr, nI0_fiterr, beta0_fiterr, beta1_fiterr = minuit_SEIR.errors[
        "dayL"], minuit_SEIR.errors["nI0"], minuit_SEIR.errors["beta0"], minuit_SEIR.errors["beta1"]
    if dayL_fit > 208:
        dayL_fit = 208
    for name in minuit_SEIR.parameters:
        print("Fit value (exp): {0} = {1:.5f} +/- {2:.5f}".format(name,
                                                                  minuit_SEIR.values[name], minuit_SEIR.errors[name]))
    chi2 = minuit_SEIR.fmin.fval
    Ndof = len(day[Fit_StartDay:Fit_EndDay]) - len(minuit_SEIR.args)
    Prob = stats.chi2.sf(chi2, Ndof)
    print(
        f"  SEIR Model fit:  Prob(Chi2={chi2:6.1f}, Ndof={Ndof:3d}) = {Prob:7.5f}")

    # Plot fitted model on top of data extending in time:
    ax_fit.plot(day[Fit_StartDay:Fit_EndDay], func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay], dayL_fit, nI0_fit,
                                                                 beta0_fit, beta1_fit, lambdaE_fit, lambdaI_fit), 'green', linewidth=2.0, label='Fit with SEIR Model')
    ax_fit.plot(day[Fit_StartDay:Fit_EndDay+15], func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay+15], dayL_fit,
                                                                    nI0_fit, beta0_fit, beta1_fit, lambdaE_fit, lambdaI_fit), 'green', linewidth=2.0, linestyle="dotted")
    ax_fit.legend(loc=(0.03, 0.75), fontsize=12)

    # Plot an "envelope" of possible predictions:
    ax_fit.plot(day[Fit_StartDay:Fit_EndDay+10], func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay+10], dayL_fit, nI0_fit,
                                                                    beta0_fit, beta1_fit+1*ebeta1_fit, lambdaE_fit, lambdaI_fit), 'green', linewidth=1.0, linestyle="dotted")
    ax_fit.plot(day[Fit_StartDay:Fit_EndDay+10], func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay+10], dayL_fit, nI0_fit,
                                                                    beta0_fit, beta1_fit-1*ebeta1_fit, lambdaE_fit, lambdaI_fit), 'green', linewidth=1.0, linestyle="dotted")
    ax_fit.fill_between(day[Fit_StartDay:Fit_EndDay+10], func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay+10], dayL_fit, nI0_fit, beta0_fit, beta1_fit+1*ebeta1_fit, lambdaE_fit,
                                                                            lambdaI_fit), func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay+10], dayL_fit, nI0_fit, beta0_fit, beta1_fit-1*ebeta1_fit, lambdaE_fit, lambdaI_fit), color='green', alpha=0.3)

    ax_fit.set_title(f"Fit of outbreak in {case['Name']}")
    d_fit = {'SEIR-model': "",
             'Prob Chi2': f"{Prob:.5f}",
             r'$\beta_0$      ': f"{minuit_SEIR.values['beta0']:.4f}+-{minuit_SEIR.errors['beta0']:.4f}",
             r'$\beta_1$      ': f"{minuit_SEIR.values['beta1']:.4f}+-{minuit_SEIR.errors['beta1']:.4f}",
             "Lockdown": f"{data_posi.iloc[int(dayL_fit)].name}, ({int(dayL_fit)})"}
    add_text_to_ax(0.05, 0.72, nice_string_output(
        d_fit, decimals=0), ax=ax_fit, fontsize=9)

    if (case['doFitSIR'] or case['doFitSEIR']):
        plt.tight_layout()
        plt.show(block=False)
        if (save_plots):
            plt.savefig(f'figures/{case["Name"]}_modelFit.pdf')

    fig_res, ax_res = plt.subplots(2, figsize=(9, 9))
    ax_res[0].errorbar(day[Fit_StartDay:Fit_EndDay+10], (nPos_aarhus[Fit_StartDay:Fit_EndDay+10]-func_SEIRmodel_vec(day[Fit_StartDay:Fit_EndDay+10], dayL_fit, nI0_fit,
                                                                                beta0_fit, beta1_fit+1*ebeta1_fit, lambdaE_fit, lambdaI_fit)), enPos_aarhus[Fit_StartDay:Fit_EndDay+10],
                       fmt='.', linewidth=2, color="red", label='Residuals)')
    ax_res[0].plot(day[Fit_StartDay:Fit_EndDay+10],
                   np.zeros(len(day[Fit_StartDay:Fit_EndDay+10])), 'k--')
    ax_res[0].set(xlabel='Day after day 0', ylabel="fit residual",
                  title=f"Residuals for {case['Name']}")
    ax_res[0].legend()
    simulation = True
    if simulation:
        days_pos = day[int(np.rint(dayL_fit)):]
        val = minuit_SEIR.args
        from tqdm import tqdm

        def simul(days, vals, cov, N=int(1e5)):
            ys = []
            mu = []
            sig_up = []
            sig_down = []
            sig2_up, sig2_down = [], []
            means = [vals[0], vals[1], vals[2], vals[3]]
            vals = np.random.multivariate_normal(means, cov, size=N).T
            day_L = vals[0]
            n_I0 = vals[1]
            beta_0 = vals[2]
            beta_1 = vals[3]
            print('Simulating MC')
            for i in tqdm(range(N)):
                ys.append(func_SEIRmodel(
                    days, day_L[i], n_I0[i], beta_0[i], beta_1[i], lambdaE_fit, lambdaI_fit))
            ys = np.array(ys)
            ys = ys.T
            for day in ys:
                mu.append(np.mean(day))
                per = np.quantile(day, [0.5+0.34, 0.5-0.34])
                per2 = np.quantile(day, [0.5+0.49, 0.5-0.49])
                sig_up.append(per[0])
                sig_down.append(per[1])
                sig2_up.append(per2[0])
                sig2_down.append(per2[1])
            return np.array(mu), np.array(sig_up), np.array(sig_down), np.array(sig2_up), np.array(sig2_down)
        # playtime tomorrow
        multi = False
        if not multi:
            mu, sigup, sigdown, sig2up, sig2down = simul(days=days_pos, vals=minuit_SEIR.args,
                                                         cov=minuit_SEIR.matrix())
        else:
            import multiprocessing as mp
            import os
            mus, sigs = [], []
            ps = []

            def p(x, txt='Hello'):
                print(txt+x)
                return(x)
            for _ in range(os.cpu_count()):
                # p = mp.Process(target=simul, args=[days_pos)
                p = mp.Process(target=p, args=['Ciara'])
                p.start()
                ps.append(p)
            for process in ps:
                process.join()
        ax_res[1].errorbar(day[Fit_StartDay:Fit_EndDay], nPos_aarhus[Fit_StartDay:Fit_EndDay], yerr=enPos_aarhus[Fit_StartDay:Fit_EndDay],
                           fmt='.', linewidth=2, color="red", alpha=0.8, label='Newly infected (scaled to 3000 tests)')
        ax_res[1].errorbar(day[Fit_EndDay:], nPos_aarhus[Fit_EndDay:], yerr=enPos_aarhus[Fit_EndDay:],
                           fmt='.', linewidth=2, color="purple", alpha=0.8, label='Points for evaluating prediction')
        diff = Fit_EndDay-int(np.rint(dayL_fit))
        ax_res[1].plot(days_pos[:diff+1], mu[:diff+1],
                       'g-', label='Central values')
        ax_res[1].plot(days_pos[diff:], mu[diff:],
                       color='green', linestyle='dotted')
        ax_res[1].plot(days_pos, sigup, 'g--',  label='One sigma deviation')
        ax_res[1].plot(days_pos, sigdown, "g--")
        ax_res[1].fill_between(days_pos, sigup, sigdown,
                               color='green', alpha=0.4)
        ax_res[1].plot(days_pos, sig2up, 'g--',  label='Two sigma deviation')
        ax_res[1].plot(days_pos, sig2down, "g--")
        ax_res[1].fill_between(days_pos, sig2up, sig2down,
                               color='darkgreen', alpha=0.2)
        ax_res[1].set(xlabel='Day after March 1st',
                      ylabel="Scaled cases", title="MC errors")
        ax_res[1].vlines(dayL_fit, 0, max(nPos_aarhus[150:]),
                         linestyles='dashed', alpha=0.6, label='Fitted lockdown')
        ax_res[1].vlines(Fit_EndDay-0.5, 0, max(nPos_aarhus[150:]),
                         linestyles='solid', label='Extrapolating from')
        ax_res[1].legend(loc='best', fontsize=9)
        delay = diff
        case_pos = nPos_aarhus[int(np.rint(dayL_fit))+delay:]
        pos_err = np.sqrt(enPos_aarhus[int(np.rint(
            dayL_fit))+delay:]**2-case['SystError']**2)
        mu, sigup, sigdown = mu[delay:], sigup[delay:], sigdown[delay:]
        chi2list = 0
        diflist = case_pos-mu
        k = 0
        for dif in diflist:
            if dif > 0:
                chi2list += (mu[k]-case_pos[k])**2 / \
                    ((pos_err[k]**2+sigup[k]**2))
            if dif < 0:
                chi2list += (mu[k]-case_pos[k])**2 / \
                    ((pos_err[k]**2+sigdown[k]**2))
            k += 1
        chi2 = chi2list
        Ndof = len(case_pos)-len(minuit_SEIR.np_errors())
        Prob = stats.chi2.sf(chi2, Ndof)
        d_res = {'Chi2': f"{chi2:3.1f}",
                 'Ndof': f"{Ndof}",
                 'Prob': f"{Prob:1.6f}"}
        add_text_to_ax(0.05, 0.95, nice_string_output(
            d_res, decimals=0), ax=ax_res[1], fontsize=9)
    fig_res.tight_layout()
    fig_res.show()
# Plot if any fits are performed:
# -------------------------------

# ----------------------------------------------------------------- #
# Fit to data with SIR and SIER model:
# ----------------------------------------------------------------- #

try:
    __IPYTHON__
except:
    input('Press Enter to Exit!')


# 66. Plus One
"""
Given a non-empty array of digits representing a non-negative integer, increment one to the integer.

The digits are stored such that the most significant digit is at the head of the list,
and each element in the array contains a single digit.

You may assume the integer does not contain any leading zero, except the number 0 itself.

Input: [9,9,9]
Output: [1,0,0,0]
"""
class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        carry = 1
        for i in range(len(digits) - 1 , -1, -1):
            element = digits[i] + carry
            if element > 9:
                digits[i] = element % 10
                carry = 1
            else:
                digits[i] = element
                carry = 0
        if carry == 1:
            digits = [1] + digits
        return digits