#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 15 15:28:37 2020

  Individual shale properties, indicated by an author name, are RETURNED
  starting with (current porosity, current depth, current age,  grain density, water density.)
  Also inferred or guessed (surface paleo-temperature maximum, paleo geothermal gradient,
  overburden, water pressure, and resultant sigma==S-p.)

  UNITS: porosity:fractional, depth:km, age:million years, temperatures:Kelvin or centigrade,
      geothermal gradients: deg K/m==deg C/m, densities: kg/m**3,
      overburden and pressure: kgf/m**2
Ref 00  Simple quantitative evaluation of porosity of argillaceous sediments at various depths of burial
        Rashid D.Dzevanshir1Leonid A.Buryakovskiy1George V.Chilingarian2   \
        Sedimentary Geology Volume 46, Issues 3–4, February 1986, Pages 169-175 \
        Relationship of porosity (φ) to depth of burial (D, in m), geologic age (A, in millions of years),\
        and lithology (ratio of thickness of shales/total thickness of terrigenous deposits = R)\
        has been developed by the writers, which gives satisfactory results: where φ0 = initial\
        porosity of the argillaceous sediment. A nomogram has been prepared for an easy
        solution of the above equation.
Ref 0        #https://sci-hub.se/   https://arxiv.org/    <<free preprints !
Ref 1 -  #https://www.researchgate.net/publication/341496386_AN_EASILY_USED_MATHEMATICAL\
    #_   MODEL_OF_POROSITY_CHANGE_WITH_DEPTH_AND_GEOLOGIC_TIME_IN_DEEP_SHALE_COMPACTION
    #    May 2020 International Journal of GEOMATE 19(73):108-115
    #    Avirut Puttiwongrak, P. H. Giao, Sakanann Vann
Ref 2    #https://en.wikipedia.org/wiki/Geologic_temperature_record#Overall_view
Ref 3    https://www.britannica.com/science/seawater/Density-of-seawater-and-pressure
Ref 4    #http://dandebat.dk/eng-klima5.htm  History of theEarth's Climate. T-pleistocene = 15 C.
Ref 5    KoichiAoyagiTadashiAsakawa
         Primary migration theory of petroleum and its application to petroleum exploration
         Organic Geochemistry Volume 2, Issue 1, January 1980, Pages 33-43
Ref 6    Geothermal gradient, Wikipedia
Ref 7    Cory H. Christie; Seiichi Nagihara, Geothermal gradients of the northern
         continental shelf of the Gulf of Mexico, Geosphere (2016) 12 (1): 26–34.
Ref 8    James W. Schmoker, Donald L. Gautier, Compaction of basin sediments:
         Modeling based on time‐temperature history, J Geophysical Research Solid Earth
         Volume 94, Issue B6 10 June 198
Ref 9    L. F. Athy, Density, Porosity, and Compaction of Sedimentary Rocks1,
         AAPG Bulletin (1930) 14 (1): 1–24.
Ref 10   B.Velde, Compaction trends of clay-rich deep sea sediments. Marine Geology,
         Volume 133, Issues 3–4, August 1996, Pages 193-201
Ref 11   DAVID BLACKWELL and MARIA RICHARDS,Calibration of the AAPG Geothermal
         Survey of North America BHT Data Base, AAPG04 Blackwell_and_Richards.pdf
         10 June 1989 Pages 7379-7386
Ref 12   Stephen Ehrenberg,P H Nadeau, Øyvind Steen, Petroleum reservoir porosity
         versus depth: Influence of geological age, Article in AAPG Bulletin ·
         October 2009DOI: 10.1306/06120908163
Ref 13   https://ui.adsabs.harvard.edu/abs/1990GeoRL..17.2073B/abstract
Ref 14   Berner, Ulrich; Bertrand, Philipp,Evaluation of the paleo-geothermal
         gradient at Site 768 (Sulu Sea), Geophysical Research Letters, Volume 17,
         Issue 11, p. 2073-2075, Pub Date: 1990. DOI: 10.1029/GL017i011p02073
         Bibcode: 1990GeoRL..17.2073B  (250 cen/ km )
Ref15    Jacek A.Majorowicz, Ashton F.Embry,   Present heat flow and paleo-geothermal
         regime in the Canadian Arctic margin: analysis of industrial thermal data
         and coalification gradients, Tectonophysics Volume 291, Issues 1–4, 15
         June 1998, Pages 141-159.  (.028+-9 C/km)
Ref 16   Sulu Sea bottom 55 deg F. https://www.history.noaa.gov/stories_tales/lukensphil.html
Ref 17   70-90C ~ 2-2.5 km. Compaction and rock properties of Mesozoic and
         Cenozoic mudstones and shales, northern North Sea
         M. K. Zadeh, N H Mondol,J Jahren Marine and Petroleum Geology
         Volume 76, September 2016, Pages 344-361
    Geologic ages / million years, for reference :
     Continental drift: https://www.youtube.com/watch?v=uLahVJNnoZ4
    GeologicAges = { 'holocene':[0.,.01], 'pleistocene':[.01,1.8], 'pliocene':[1.8,5.3], \
            'miocene':[5.3,23.], 'neogene':[2.58,23.03], 'eocene':[33.7,54.8], \
            'paleogene':[65,105.], 'cretaceous':[65.5,145.5], \
            'triassic':[201.,252.], 'permian':[252.,299.], \
            'pennsylvanian':[299,323], 'carboniferous':[299.,359.] }
@author: ed

"""
#import copy
import numpy as np

def shale( shale_name ):
    #https://sci-hub.se/   https://arxiv.org/    <<free preprints !
    #https://arxiv.org/    <<free preprints
    print(shale_name)

    # Names of shales in Puttiwongrak order:
    ShaleNames       = [ 'Akita',  'Makran1','Makran2', '\"SuluSea\"', 'Oklahoma', 'Maracaibo', 'ODP-DSDP' ]
    AuthorDate = [ 'Aoyagi etal. 1980', 'Fowler etal 1985', 'Fowler etal 1985','Velde 1996','Athy 1930','Hedberg 1936', 'Velde 1996']
    #print 'ShaleNames = ', ShaleNames
    ShaleNumber = ShaleNames.index( shale_name )
    #RETURN #1
    #print 'shale_name, ShaleNumber = ', shale_name, ShaleNumber

    # Depth in kilometers, in Puttiwongrak order. 1ft = .0003048km:
    DepthRanges = [ [.2, 3.], [0.30, 4.47], [ 0.36, 3.99 ], [.05, 4.], [.425, 2.], [.0887, 1.882], [.0,.5] ]
    DepthRanges[ 3] = [.05,5.]
    #RETURN #2
    #
    # Geologic ages are millions of years BP, in  Puttiwongrak order :
    AgeRanges = [ [ 5., 145.5 ], [ 2.58, 66. ], [2.58, 66. ], [ .01, 23. ], [ 254., 323. ],\
                  [ 2.58, 66. ], [ .1, 6. ]   ]
    #RETURN #3
    AgeName  = ['Miocene-Cretaceous', 'Paleogene-Neogene', 'Paleogene-Neogene',\
                 'Holocene-Miocene', 'Pennsylvanian-Permian','Paleogene-Neogene',\
                 'Northeastern Thailand']

    # Units are fractional porosity and km**{-1}, in Puttiwongrak order:
    PorosityDepthParams = { 'Akita':[ .72, .656,0. ] , 'Makran1':[.7, -.796, .065 ] ,'Makran2':[.7,-1.239, .171 ], \
       '\"SuluSea\"':[ .56, .486, 0. ] , 'Oklahoma':[ .48, 1.457, 0. ]  ,          \
       'Maracaibo':[ .41, .698, 0.] , 'ODP-DSDP':[ .0875, .071, 0. ] }
    #RETURN # 4
    #
    #Eocene excess = 15 deg C,Miocene= +10, Pliocene = +4. Above present 1960-1990 average = 14 deg C.
    #Mud line deg C using global maximum paleo-temperatures. Pleistocene= 14 C maximum:
    #Mindanao av annual temperature = 31.5 deg C.
    #https://www.sciencedirect.com/science/article/abs/pii/S0967064506003006#:~\
    #:text=Thus%2C%20the%20Sulu%20Sea%20basin%20is%20unique%2C%20with,depths%20be\
    #low%201000%20m%20%28Rathburn%20et%20al.%2C%201996%29.
    #Ref 16   Sulu Sea bottom 55 deg F. https://www.history.noaa.gov/stories_tales/lukensphil.html
    # Continental drift video: https://www.youtube.com/watch?v=uLahVJNnoZ4
    Cmud0, Cmud1, Cmud2, Cmud3, Cmud4, Cmud5 = (3.+14. +13.)/2. ,3. ,3.,  (13.+10.+14.)/2., (13.+14.+7.)/2., (3.+ 14.+13.)/2.
    Cmud3 = 12.7  #(12.7+31.5)/2.   #12.7
    Cmud6 = 4.  #14+13.
    #Cmud7 = (3.+14.+13.)/2.
    PaleoMudlineT = np.array([  Cmud0, Cmud1, Cmud2, Cmud3, Cmud4, Cmud5, Cmud6 ])
    #RETURN #5
    #
    # Assumed paleo geothermal gradient. See Ref 5.
    #Oil window = 50-150 C,  Gas window = 150-200 C; see:
    # https://en.wikipedia.org/wiki/Kerogen5, .05, .02 ] #deg C/m
    GeothermalGradientMax = [   .05, .03,  .03, .03, .06,.05, .03  ]

    #Better m ?:                1.1   1.0  1.0  1.0   .85  1.0
    #Better n ?:                1.0   0.7  0.6  0.5   1.0  0.9
    #RETURN #6
    #Average temperature for all wells, Deg K::
    TKavg = np.zeros( len( ShaleNames ) )

    for i in range( len( ShaleNames ) ) :
        TKavg[i] = ( PaleoMudlineT[i] + GeothermalGradientMax[i]*DepthRanges[i][1]*1000. )/2. +273.2
    TKavgavg = np.mean(TKavg)
    #RETURN #7,8
    dy_steps = 500  # number of divisions for fitting porosity vs depth
    #RETURN # 1-8 :
    Low_Temp = 40.  #Don't use data at temperatures lower than this
    Deposition_Rate = 1.  # m/1000yr= m/3.171*pow( 10.-8) sec
    return ShaleNames[ShaleNumber], ShaleNumber, AgeRanges[ ShaleNumber ], DepthRanges[ShaleNumber], \
        PorosityDepthParams[ ShaleNames[ShaleNumber] ], PaleoMudlineT[ ShaleNumber ], \
            GeothermalGradientMax[ ShaleNumber ], TKavg[ShaleNumber], TKavgavg, dy_steps,\
            AuthorDate, Low_Temp,  Deposition_Rate, AgeName[ShaleNumber]
    #
#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH_Hedberg_Maracaibo_HHHHHHHHHHHHHHHHHHHHHHH
    #Hedberg, H.D., 1936. Gravitational compaction of clays and shales.
    #American Journal of Science 31 (184), 241–287. p 279 for rho_g and p-254 for porosity-depth Maricaibo:
    #y =Depth ft, x=fractional porosity. rhog = 2.666, rhow = 1.
    y = 291.,472.,497.,511.,862.,        922.,1637.,1805.,1920.,2031.,  2146.,2146.,2200.,2480.,2605.,\
        2780.,2818.,2996.,3015.,3094.,  3293.,3313.,3353.,3353.,3521.,  3702.,3973.,4336.,4608.,4849., \
        5007.,5035.,5389.,5502.,6013.,  6081.,6175.

    x = .3363,.3583,.3385,.3314,.3347,  .3133,.2776,.2738,.2875,.2662,  .2887,.2590,.2468,.2519,.2494, \
        .2532,.2288,.2423,.2561,.2489,  .2063,.2124,.1780,.1813,.2060,  .2220,.1855,.1777,.1680,.1420, \
        .1460,.1280,.1303,.1364,.0907,  .0918,.1060
#
#
#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA_Aoyagi__Akita_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    #shale( 'Akita' )
#         Y_values = np.array([222, 284, 308.5, 333, 358, 411, 477, 518, 880, 1080, 1259])
#         X_values = np.array([0.1282, 0.2308, 0.2650, 0.3120 , 0.3547, 0.4530, 0.5556,\
#                    0.6154, 0.8932, 0.9103, 0.9316])

#
#^^^^^^^^^^^^^^^^^^_Makran_Input_Data_^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    # x1 is abyssal plain porosity:
    x1 = np.array( [ .46,.31,.11,.46,.31,.29,.21,.15,.12,.35,.20,.14,.07,\
      .38,.16,.53,.36,.22,.11,.46,.24,.08,.07,.12,.07,.69,.41,.23,.13 ] )
    # y1 is abyssal plain depth in km:
    y1 = np.array( [ 0.30,0.97,1.86,0.30,0.97,1.53,1.71,2.37,3.23,0.92,1.84,\
      2.52,4.47,0.50,3.08,0.28,1.66,2.03,3.61,0.44,1.45,3.97,4.21,2.55,3.78,\
      0.05,0.31,1.72,3.04 ] )
    # x2 is accretionary prism porosity:
    x2 = np.array([.29,.16,.11,.07,.11,.07,.67,.28,.17,.15,.42,.18,.46,\
                           .35,.19,.40,.20,.16,.08,.50,.18,.12,.09 ] )
    # y2 is accretionary prism depth in km:
    y2   = np.array([0.80,1.64,2.20,3.49,2.35,3.99,0.21,0.84,1.84,1.57,0.55,\
                1.12,0.23,0.45,0.92,0.45,1.11,1.75,3.13,0.36,1.04,1.76,2.81  ])
    #
    # Here y1s increases monotonically. The matching x1s aren't monotonic:
    #y1s,x1s   = map( np.array, zip(*sorted( zip(y1 ,x1 ) ) ) )
    #print ' y1s,x1s = ', y1s, x1s
    #
    #
    #
    #xxxxxxxxxxxxxxxxxxxxxxxxxxx_Dutta_Gulf_of_Mexico_xxxxxxxxxxxxxxxxxxxxxxxxx
    #TANIMA DUTTA , GARY MAVKO , and TAPAN MUKERJI , Stanford Rock Physics Laboratory
    #T IM L ANE , BP Exploration and Production Technology Group
    #Compaction trends for shale and clean sandstone iFor 0-6200 ft. No geologic age.
    #Coefficients of exponential fits using a general exponential equation:
    #Z = depth below mud-line (DBML) in ft.
    # phi = a*e^(b*z) = c*e^(d*z) a,b,c,d = .2875,-.007784,.4384,-.0001761
    #GreenCanyon, Gulf of Mexico << may give T and age.

    #xxxxxxxxxxxxxxxxxxxxxxxxxRevil_South Eugene Islandxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    #
    #Andre Revil, L. M. Cathles The Porosity-Depth Pattern defined by 40 wells in South Eugene Island
    #Block 330 area, and its relation to pore pressure, fluid leakage, and seal
    #migration 900m to 1950m Block 314,330. rhog, rhow = 2.65, 1.1
    #The minibasin is well described in Ph.D.
    #dissertations and in the published literature (cf., Holland et al. 1990; Alexander, 1995;
    #Alexander and Flemings, 1995; Coelho, 1997; Alexander and Handschy, 1998).
    #Holland, D. S., J. B. Leedy, and D. R. Lammelin, 1990, Eugene Island Block 330 field -
    #USA, offshore Louisiana, in Beaumont, E.A., and Foster, N.H., eds., Structural
    #Traps; III, Tectonic fold and fault traps,
    #Alexander, L. L., and P. B. Flemings, 1995, Geologic evolution of a Pliocene-Pleistocene
    #salt withdrawal mini-basin: Eugene Island Block 330, offshore Louisiana, AAPG
    #Bull., v. 79, p. 1737-1756.
    #Alexander, L. L., and J. W. Handschy, 1998, Fluid flow in a faulted reservoir system:
    #fault trap analysis for the Block 330 field in Eugene Island, South Addition,
    #offshore Louisiana, AAPG Bull., v. 82, p. 387-411.
    #Alexander, L. L., 1995, Geologic evolution and stratigraphic controls on the fluid flow of
    #10the Eugene Island Block
    #xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_Athy_Oklahoma_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

    #L. F. Athy, DENSITY, POROSITY, AND COMPACTION OFSEDIMENTARY ROCKS,BULLETIN
    #of the AMERICAN ASSOCIATION OF PETROLEUM GEOLOGISTS v14, Number 1, pp 1-24.
    #Figure 2:
    Density = 1.40, 2.08, 2.245, 2.38, 2.480,  2.56, 2.60,  2.615, 2.63
    Depth   =    0., 1750.,2000.,  3200., 4000., 5200., 6000., 6400.
    # p = p { e - bx ), p = .48.   Figure 3, depth ft. :
    Phi   = .48, .26,   .20,  .126,   .075,  .05,   .03,   .022
    Depth = 0., 1400., 2000., 3000., 4000., 5200., 6000., 7000.

    #    In Figure 2, densities of samples from wells in the Mervine, South
    #Ponca, Thomas, Garber, and Blackwell fields are plotted. The sed-
    #iments range from the Enid Red-beds of Permian age to the Cherokee
    #shales in the base of the .Pennsylvanian, a stratigraphic range of about
    #4,000 feet.
    #If it is granted that the compaction depth relations in north-central
    #Oklahoma are approximately correct as given in this paper, then abou
    #1,400 feet of Permian and younger sediments once covered the area
    #around Garber, Oklahoma, nearly 2,000 feet were present at Thomas
    #and Tonkawa, and 2,400-2,500 feet at Ponca City.
    #By applying the compaction-depth data derived from the areas just
    #named to the Nowata-Chelsea district southeast of Bartlesville, Okla-
    #homa, where densities range from 2.47 to 2.51 at depths ranging from
    #150 to 400 feet in the lower Pennsylvanian, it is estimated that the eroded
    #overburden is 4,000-4,500 feet. These figures indicate that the total
    #stratigraphic thickness deposited above the Oswego limestone in the
    #lower part of the Pennsylvanian was 1,000-1,500 feet less at Chelsea
    #than at Garber.
    #The compaction noted by Hedberg in Hamilton County, Kansas, is
    #much less per thousand feet of burial than that observed by the writer
    #in Kay, Noble, and Garfield counties, in Oklahoma. Either there were
    #inherent differences in the character of the sediments in the two areas
    #which cause their compressibilities to differ, or some other factors, such
    #as the age of the formations or the nearness to centers of folding, cause
    #the difference.

    #88888888888888888_Aoyagi_Akita_8888888888888888888888888888888888888888888

    DepthA = 0.,  440.,  790., 1270.,1850., 2620.
    PhiA   = .75,  .50,  .40,  .30,   .20,   .10

    #88888888888888888_Aoyagi_Akita_8888888888888888888888888888888888888888888


#!/usr/bin/env python3

import psycopg2

def db_query(query, db_name, user):
    """
    Connects to the given DB and runs the given query.

    Arguments:
        -query: string, required: the query (or view) to be requested
        -db_name: string, required: the database that will be connected to
        -user: string, required: username to be used when logging into DB
    Returns:
        -unmodified data structure received from psycopg2 library
    """

    # Attempt connection to DB with given parameters
    try:
        conn = psycopg2.connect(dbname=db_name, user=user)
    except psycopg2.Error as e:
        print(e)
        raise SystemExit

    # Create cursor and try to execute given query
    # and return fetched data
    cur = conn.cursor()
    try:
        cur.execute(query)
    except psycopg2.Error as e:
        print(e)
        conn.close()
    else:
        return cur.fetchall()
        cur.close()
        conn.close()

# Output results of query for the most popular articles of all time
q1 = db_query('select * from view_select_popular_articles',
              'news', 'vagrant')

print('\nMost popular articles of all time:\n')
for entry in q1:
    print('{} - {} views'.format(entry[0], entry[1]))

# Output results of query for most popular authors of all time
q2 = db_query('select * from view_select_popular_authors',
              'news', 'vagrant')

print('\nMost popular authors of all time:\n')
for entry in q2:
    print('{} - {} views'.format(entry[0], entry[1]))

# Output results of query for days with error % greather than 1
q3 = db_query('select * from view_select_error_percent',
              'news', 'vagrant')

print('\nDays with error count over 1%:\n')
for entry in q3:
    print('{} - {}%'.format(entry[0], entry[1]))


import numpy as np

from nd2reader import ND2Reader
from pathlib import Path
from tifffile import imwrite
from tqdm.auto import tqdm

class StitchWell:

    def __init__(self, path):

        path = Path(path)

        if path.is_file():

            self.files = [path]

        elif path.is_dir():

            self.files = [file for file in path.iterdir() if
                          file.is_file() and file.suffix == '.nd2']

        self.images = None
        self.raw_metadata = None
        self.axes = None

    def read_nd2(self, file_index):

        file = open(self.files[file_index], 'rb')
        images = ND2Reader(file)
        axes = dict(images.sizes)
        if 'v' in axes.keys():
            images.iter_axes = 'v'
            axes.pop('v')
        if axes['t'] == 1:
            axes.pop('t')
        axes = ''.join(reversed(list(axes.keys())))
        images.bundle_axes = axes

        raw_metadata = images.parser._raw_metadata

        return images, raw_metadata, axes

    def calculate_total_margins(self, width, height):

        x_total_margin = self.images.metadata['width'] - width
        y_total_margin = self.images.metadata['height'] - height
        total_margins = (x_total_margin, y_total_margin)

        return total_margins

    def calculate_margins(self, width, height):

        total_margins = self.calculate_total_margins(width, height)

        x_left_margin = int(np.floor(total_margins[0] / 2))
        x_right_margin = x_left_margin + width
        x_margins = (x_left_margin, x_right_margin)

        y_top_margin = int(np.floor(total_margins[1] / 2))
        y_bottom_margin = y_top_margin + height
        y_margins = (y_top_margin, y_bottom_margin)

        return x_margins, y_margins

    def stitch(self, file_index=0, overlap=0.1):

        self.images, self.raw_metadata, self.axes = self.read_nd2(file_index)

        if 'v' not in self.images.iter_axes:
            stitched = self.images[0].astype(np.uint16)

            return stitched

        positions = self.raw_metadata.image_metadata[b'SLxExperiment'][b'uLoopPars'][b'Points'][b'']
        coords = np.array([(position[b'dPosX'], position[b'dPosY']) for position in positions]).T

        theta = self.raw_metadata.image_metadata_sequence[b'SLxPictureMetadata'][b'dAngle']
        c, s = np.cos(theta), np.sin(theta)
        r = np.array(((c, -s), (s, c)))
        x, y = np.rint(np.dot(r, coords))

        x_dim = round(np.ptp(x) / abs(x[0] - x[1])) + 1
        y_dim = round(np.ptp(y) / abs(x[0] - x[1])) + 1

        x_scaled = np.rint((x - min(x)) / (np.ptp(x) / (x_dim - 1)))
        y_scaled = np.rint((y - min(y)) / (np.ptp(y) / (y_dim - 1)))

        width = round(self.images.metadata['width'] * (1 - overlap))
        height = round(self.images.metadata['height'] * (1 - overlap))
        x_margins, y_margins = self.calculate_margins(width, height)

        abs_dim = (*self.images.frame_shape[:-2], y_dim * height, x_dim * width)

        stitched = np.zeros(abs_dim, dtype=np.uint16)

        for i in tqdm(self.images.metadata['fields_of_view'], desc='Image Progress'):
            x_array = int(x_scaled[i] * width)
            y_array = int(abs_dim[-2] - y_scaled[i] * height)

            stitched[..., y_array - height:y_array, x_array:x_array + width] = \
                self.images[i][..., y_margins[0]:y_margins[1], x_margins[0]:x_margins[1]]

        return stitched

    def save_tiff(self, out_dir, overlap=0.1):

        for fileIndex, file in enumerate(tqdm(self.files, desc='Total Progress')):
            stitched = self.stitch(fileIndex, overlap)
            imwrite(Path(out_dir).joinpath(file.with_suffix('.tif').name), stitched,
                    metadata={'axes': self.axes}, ome=True, photometric='minisblack')


from math import sqrt

class Node:
    def __init__(self, x, y, direction, cost, node=None, ):
        self.x = x
        self.y = y
        self.direction = direction
        self.node = node
        self.node_list = list()
        self.cost = cost
        # self.position = position.copy()

class PathAlgorithms:
    def __init__(self, snake, apple):
        self.apple = apple
        self.snake = snake
        self.new_map = None
        self.init_map()
        self.load_map()
        self.error = None

    def init_map(self):
        n = 30
        m = 30
        self.new_map = [0] * n
        for i in range(n):
            self.new_map[i] = [0] * m

    def load_map(self):
        index = 0
        for x, y in self.snake.body:
            if index < len(self.snake.body) - 1:
                self.new_map[x][y] = -1
            index += 1

    def find_path(self, nodes):
        pass

    def check_box(self, x, y, direction, snake_x, snake_y, nodes):
        pass

    def algorithm(self):
        pass

class DijkstraAlgorithm(PathAlgorithms):
    def find_path(self, nodes):
        new_node = list()
        target_x, target_y = self.apple.x, self.apple.y
        snake_x, snake_y = self.snake.body[-1]
        # add new node
        new_node.append(self.check_box(nodes.x, nodes.y - 1, 3, snake_x, snake_y, nodes))
        new_node.append(self.check_box(nodes.x, nodes.y + 1, 2, snake_x, snake_y, nodes))
        new_node.append(self.check_box(nodes.x + 1, nodes.y, 1, snake_x, snake_y, nodes))
        new_node.append(self.check_box(nodes.x - 1, nodes.y, 0, snake_x, snake_y, nodes))

        # add to nodes only those with a value
        for val in new_node:
            if val:
                nodes.node_list.append(val)

        #
        for node in nodes.node_list:
            if node.x == target_x and target_y == node.y:
                self.new_map[node.x][node.y] = 42
                return node
        return None

    def check_box(self, x, y, direction, snake_x, snake_y, nodes):
        # check if the nodes is in the map
        if 0 <= x < 30 and 0 <= y < 30:
            # check if the x and y is not the head of snake
            if x != snake_x or y != snake_y:
                # check if the case of the node is empty
                if self.new_map[x][y] == 0:
                    # create the new node
                    node = Node(x, y, direction, nodes.cost+1, nodes)
                    self.new_map[x][y] = node.cost
                    return node

    def algorithm(self):
        # initialise the nodes
        target_not_found = True
        target = False

        nodes = list()
        snake_x, snake_y = self.snake.body[-1]
        nodes.append([Node(snake_x, snake_y, 0, 0)])
        self.find_path(nodes[0][0])
        nodes.append(nodes[0][0].node_list)

        while target_not_found and self.error is None:
            nodes.append(list())
            for node in nodes[-2]:
                target = self.find_path(node)
                if target:
                    # print("found !")
                    target_not_found = False
                    break
                else:
                    nodes[-1].extend(node.node_list)
            if len(nodes[-1]) == 0 and target_not_found:
                self.error = "Not found"

        if self.error is None:
            path = list()
            while True:
                path.append(target.direction)
                target = target.node
                if target == nodes[0][0]:
                    break
            print(path)
            return path

class AStar(DijkstraAlgorithm):
    def check_box(self, x, y, direction, snake_x, snake_y, nodes):
        # check if the node is in the map
        if 0 <= x < 30 and 0 <= y < 30:
            # check if the node is not at the snake's head
            if x != snake_x or y != snake_y:
                # check if the node's case is empty
                if self.new_map[x][y] == 0:
                    # calcul the distance from the apple
                    distance = sqrt((x-self.apple.x)**2 + (y-self.apple.y)**2)
                    cost = nodes.cost+1 + distance
                    node = Node(x, y, direction, cost, nodes)
                    self.new_map[x][y] = cost
                    return node

    def nodes_sorting(self, nodes, result):
        if len(nodes):
            min_cost = nodes[0].cost
            closest_node = nodes[0]
            for node in nodes:
                if node.cost < min_cost:
                    min_cost = node.cost
                    closest_node = node
            # add the closest node to the result
            result.append(closest_node)
            # remove the closest nodes to the nodes
            nodes.remove(closest_node)
            # redo the process
            result = self.nodes_sorting(nodes, result)
        return result

    def algorithm(self):
        # initialize the nodes
        nodes = list()
        snake_x, snake_y = self.snake.body[-1]
        initial_node = Node(snake_x, snake_y, 0, 0)
        nodes.append(initial_node)
        self.find_path(nodes[0])
        nodes.extend(nodes[0].node_list)
        target = False

        while self.error is None:
            result = list()
            nodes = self.nodes_sorting(nodes, result)
            try:
                target = self.find_path(nodes[0])
                # If we found the apple, move out from the loop
                if target:
                    break
                else:
                    # add the new node
                    nodes.extend(nodes[0].node_list)
                    # remove the old one
                    nodes.pop(0)
            except IndexError:
                self.error = "Not Found"

        if self.error is None:
            path = list()
            while True:
                path.append(target.direction)
                target = target.node
                if target == initial_node:
                    break
            print(path)
            return path


def profit(stock_prices):
    # Start minimum price marker at first price
    min_stock_price = stock_prices[0]

    # Start off with a profit of zero
    max_profit = 0

    for price in stock_prices:
        # Check to set the lowest stock price so far
        min_stock_price = min(min_stock_price, price)

        # Check the current price against our minimum for a profit
        # comparison against the max_profit
        comparison_profit = price - min_stock_price

        # Compare against our max_profit so far
        max_profit = max(max_profit, comparison_profit)

    return max_profit
print(profit([30,22,21,5]))


# 외벽의 길이 n, 취약 지점의 위치가 담긴 배열 weak, 각 친구가 1시간 동안 이동할 수 있는 거리가 담긴 배열 dist
from itertools import permutations
def solution(n, weak, dist):
    weak_len, dist_len = len(weak), len(dist)
    answer = dist_len + 1

    # 원형 리스트를 선형 리스트로 변환한다.
    weak += [x + n for x in weak]

    for start in range(weak_len):
        for friend in permutations(dist, dist_len):
            count = 1
            reachable_position = weak[start] + friend[count -1]

            for i in range(start, start + weak_len):
                if reachable_position < weak[i]:
                    count += 1
                    if dist_len < count:
                        break
                    reachable_position = weak[i] + friend[count - 1]

            answer = min(answer, count)

    if answer == dist_len + 1:
        return -1
    return answer

코테/외벽 점검 다시 풀이.py

외벽 점검 다시 풀이.py


from cube.api import Cube
import nltk
from nltk.corpus import wordnet
import joblib
from nltk.stem import WordNetLemmatizer
import random
import torch
from pytorch_transformers import (
    BertTokenizer,
    BertForMaskedLM,
)
import gensim
model_r = gensim.models.KeyedVectors.load_word2vec_format('/data/zly/GoogleNews-vectors-negative300.bin',limit=800000, binary=True)
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForMaskedLM.from_pretrained('bert-base-uncased')

model.eval()
cube=Cube(verbose=True)
cube.load('en', tokenization=True, compound_word_expanding=False, tagging=True, lemmatization=True,parsing=False)
unigram_tagger=joblib.load("/data/zly/unigram_tagger.pkl")
lemmatizer = WordNetLemmatizer()

def convert(s):
    if (s=="NN" or  s=="NNS" or s=="NNP" or s=="NNPS"):
        return "NOUN"
    elif (s=="RB" or s=="RBR" or s=="RBS"):
        return"ADV"
    elif (s=="VB" or  s=="VBD" or s=="VBG" or s=="VBN" or s=="VBP" or s=="VBZ"):
        return "VERB"
    elif (s=="JJ" or s=="JJR" or s=="JJS"):
        return "ADJ"
    else:
        return ""
from functools import partial

def common_prefix(strings):

    if len(strings) == 1:
        return strings[0]

    prefix = strings[0]

    for string in strings[1:]:
        while string[:len(prefix)] != prefix and prefix:
            prefix = prefix[:len(prefix)-1]
        if not prefix:
            break

    return len(prefix)

def get_syn(string,ids):

    sentences=cube(string)

    tokenized_text1=['[CLS]']
    text=[]
    for sentence in sentences:
        for entry in sentence:
            text.append(entry.word)
    text.append('[SEP]')
    tokenized_text1+=text+text
    length = (len(tokenized_text1)-3)//2
    index=0
    cnt=0

    for sentence in sentences:
        for entry in sentence:
            cnt+=1
            index+=1

            if (not entry.word.replace("-"," ").replace("_"," ").isalpha()) :
                cnt-=1
                continue
            if (not cnt==ids):
                continue

            if (entry.upos=="NOUN" or entry.upos=="VERB" or entry.upos=="ADJ" or entry.upos=="ADV"):

                masked_idx = index + 1 + length
                tokenized_text=tokenized_text1.copy()
                tokenized_text[masked_idx] = '[MASK]'
                tokens_ids = tokenizer.convert_tokens_to_ids(tokenized_text)
                segments_ids =[0]*(length+2)+[1]*(length+1)
                tokens_tensor = torch.tensor([tokens_ids])
                segments_tensors = torch.tensor([segments_ids])

                if torch.cuda.is_available():
                    tokens_tensor = tokens_tensor.to('cuda')
                    segments_tensors = segments_tensors.to('cuda')
                    model.to('cuda')
                with torch.no_grad():
                    outputs = model(tokens_tensor, token_type_ids=segments_tensors)
                    predictions = outputs[0]

                topk_score, topk_index = torch.topk(predictions[0, masked_idx], 3)
                topk_tokens = tokenizer.convert_ids_to_tokens(topk_index.tolist())

                synonyms = []
                syns=set([])
                syns1=set([])

                lemma=""
                synsets=wordnet.synsets(entry.lemma)
                if (len(synsets)==0):
                    lemma=lemmatizer.lemmatize(entry.word)
                    synsets=wordnet.synsets(lemma)
                else:
                    lemma=entry.lemma
                cnt=0

                for syn in synsets:
                        for l in syn.lemmas():
                            synonyms.append(l.name())

                for word in synonyms+topk_tokens:
                    if (len(word)==1):
                        continue
                    tags=[tag[1] for tag in unigram_tagger.tag([word])]
                    if (word.lower()==entry.word or word.lower()==lemma):
                        continue
                    syn_word=word.replace("-"," ").replace("_"," ")

                    if (not all(x.isalpha() or x.isspace() for x in syn_word)
                    or ((word in topk_tokens) and(not None in tags)and (not entry.upos in [convert(tag) for tag in tags]))
                    or ((word in synonyms) and(not None in tags)and (not entry.upos in [convert(tag) for tag in tags]))
                        or (common_prefix([syn_word,entry.word])>=4 and len(syn_word)-len(lemma)<=3)):
                        continue
                    if (word in synonyms):
                        syns1.add(syn_word)
                    else:
                        syns.add(syn_word)

                list1=[]
                list2=[]
                for word in syns1:
                    if (not all(a in model_r.vocab for a in word.split())):

                        list2.append(word.split(" "))
                    else:

                        list1.append(word.split(" "))

                if (lemma in model_r.vocab):
                    list.sort(list1,key=partial(model_r.n_similarity,ws2=[lemma]),reverse=True)

                list3=[]
                list4=[]
                for word in syns:
                    if (not all(a in model_r.vocab for a in word.split())):

                        list4.append(word.split(" "))
                    else:

                        list3.append(word.split(" "))
                if (lemma in model_r.vocab):
                    list.sort(list3,key=partial(model_r.n_similarity,ws2=[lemma]),reverse=True)
                list4+=list2

                list3+=list1
                list5=[]
                for element in list3:
                    if (not lemma in model_r.vocab)or(model_r.n_similarity(element,[lemma])>0.2) or(not element in list1):
                        s=""
                        for parts in element:
                            s+=parts+" "
                        list5.append(s[:-1])

                list1=list5
                list5=[]
                for element in list4:
                    s=""
                    for parts in element:
                        s+=parts+" "
                    list5.append(s[:-1])
                if (len(list1)<5):
                    list1+=list5[0:min(len(list5),5-len(list1))]
                return list1[:5]
            else:
                return []
    return []


import unittest
import pandas as pd

class TestFactorize(unittest.TestCase):
    def test_wrong_types_raise_exception(self):
        self.cases = [1.5, "string"]
        for x in self.cases:
            with self.subTest(x=x):
                self.assertRaises(TypeError, factorize, x)

    def test_negative(self):
        self.cases = [-1, -10, -100]
        for x in self.cases:
            with self.subTest(x=x):
                self.assertRaises(ValueError, factorize, x)

    def test_zero_and_one_cases(self):
        self.cases = [[0, (0,)], [1, (1,)]]
        for x,b in self.cases:
            # print (a,b)
            with self.subTest(x=x):
                self.assertEqual(factorize (x), b)

    def test_simple_numbers(self):
        self.cases = [[3, (3,)], [13, (13,)], [29, (29,)]]
        for x,b in self.cases:
            # print (a,b)
            with self.subTest(x=x):
                self.assertEqual(factorize (x), b)

    def test_two_simple_multipliers(self):
        self.cases = [[6, (2,3)], [26, (2,13)], [121, (11,11)]]
        for x,b in self.cases:
            # print (a,b)
            with self.subTest(x=x):
                self.assertEqual(factorize (x), b)

    def test_many_multipliers(self):
        self.cases = [[1001, (7, 11, 13)], [9699690, (2, 3, 5, 7, 11, 13, 17, 19)]]
        for x,b in self.cases:
            # print (x,b)
            with self.subTest(x=x):
                # self.assertIsNone(factorize (x))
                self.assertEqual(factorize (x), b)

def factorize(x):
    """
    Factorize positive integer and return its factors.
    :type x: int,>=0
    :rtype: tuple[N],N>0
    """
    # from functools import reduce
    # return tuple(reduce(list.__add__,
    #             ([i, x//i] for i in range(1, int(x**0.5) + 1) if x % i == 0)))

if __name__=='__main__':
    # import unittest

    print(factorize(150))

    unittest.main()

homework/01 модульный тест функции factorize/01test_factorize.py


from random import random

class Car:
    def __init__(self, x, lap, maxvelocity, minimalDist):
        self.position = x
        self.lap = lap
        self.default_acc=3
        self.velocity = 5
        self.probDeacc = 0.3
        self.max_velocity = maxvelocity
        self.acceleration = 0
        self.distance = 0
        self.minDist = minimalDist

    def update(self, dt):
        self.velocity += self.acceleration * dt
        self.velocity = max(0, min(self.velocity, self.max_velocity))

        self.position += self.velocity * dt
        if self.position > self.lap:
            self.position = self.position - self.lap

    def react(self, dt):
        # default: beschleunige
        acc = self.default_acc

        # trödeln in probDeacc Fällen
        reactProb = random()
        if(reactProb < self.probDeacc):
            acc = - self.default_acc

        #s: der zu zurück legende Weg
        s = self.velocity * dt + acc * dt * dt /2
        # wenn man das Vorausfahrende FAhrzeug überholen würde dann wird abgebremst
        if(s>self.distance- self.minDist):
            self.acceleration = 2 * (self.distance - self.minDist - self.velocity * dt) / (dt * dt)
        else:
            self.acceleration = acc


# https://leetcode.com/explore/challenge/card/may-leetcoding-challenge/535/week-2-may-8th-may-14th/3326/

# An image is represented by a 2-D array of integers, each integer representing
# the pixel value of the image (from 0 to 65535).
#
# Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill,
# and a pixel value newColor, "flood fill" the image.
#
# To perform a "flood fill", consider the starting pixel, plus any pixels connected 4-directionally
# to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally
# to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all
# of the aforementioned pixels with the newColor.
#
# At the end, return the modified image.

# Example 1:
# Input:
# image = [[1,1,1],[1,1,0],[1,0,1]]
# sr = 1, sc = 1, newColor = 2
# Output: [[2,2,2],[2,2,0],[2,0,1]]
# Explanation:
# From the center of the image (with position (sr, sc) = (1, 1)), all pixels connected
# by a path of the same color as the starting pixel are colored with the new color.
# Note the bottom corner is not colored 2, because it is not 4-directionally connected
# to the starting pixel.

# Note:
# The length of image and image[0] will be in the range [1, 50].
# The given starting pixel will satisfy 0 <= sr < image.length and 0 <= sc < image[0].length.
# The value of each color in image[i][j] and newColor will be an integer in [0, 65535].

class Solution(object):
    def floodFill(self, image, sr, sc, newColor):
        """
        :type image: List[List[int]]
        :type sr: int
        :type sc: int
        :type newColor: int
        :rtype: List[List[int]]
        """
        img_h = len(image)
        img_w = len(image[0])

        visited = set()

        def get_neighbors(row, col):
            return [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]

        def fill(row, col, color, new_color):
            if row < 0 or row >= img_h:
                return
            if col < 0 or col >= img_w:
                return

            if image[row][col] != color:
                return

            if (row, col) in visited:
                return

            image[row][col] = new_color
            visited.add((row, col))

            for cell in get_neighbors(row, col):
                fill(cell[0], cell[1], color, new_color)

            return

        fill(sr, sc, image[sr][sc], newColor)

        return image


from inspect import getfullargspec as argspec
from colorsys import hsv_to_rgb

from ctypes.util import find_library
from vapoursynth import core
import vapoursynth as vs
import os.path, math                                               # noqa: E401

DIR = os.path.dirname(__file__) + '/'

mvtools2_p = find_library('mvtools')
imwri_p = find_library('imwri')

if not hasattr(core, 'mv') and mvtools2_p:
    core.std.LoadPlugin(mvtools2_p)

if not hasattr(core, 'imwri') and imwri_p:
    core.std.LoadPlugin(imwri_p)

def AddMotionLegend(flow_vis):
    main, mask = core.imwri.Read(DIR + "motion-legend.png", alpha=True)
    conv_args = {'format': flow_vis.format.id, 'matrix_s': '709'}
    y, x, z = main.height, main.width, flow_vis.height
    W, H = x * z // (8 * y) * 2, z // 8 * 2

    main = core.std.Loop(core.resize.Bilinear(main, W, H, **conv_args))
    left_incr, top_incr = flow_vis.width - W, flow_vis.height - H
    mask = core.std.Loop(core.resize.Bilinear(mask, W, H))
    M = min((left_incr // 20) * 2, (top_incr // 20) * 2)

    main = core.std.AddBorders(main, left_incr - M, M, top_incr - M, M)
    main = core.std.AssumeFPS(main, flow_vis)

    mask = core.std.AddBorders(mask, left_incr - M, M, top_incr - M, M)
    mask = core.std.AssumeFPS(mask, flow_vis)

    return core.std.MaskedMerge(flow_vis, main, mask)

def MotionMVTools(yuv_in, *args, dst=None, **kwargs):
    """Attach motion data to the clip."""

    kwargs.setdefault('badsad', 1500)
    kwargs.setdefault('zerow', 10.0)

    kwargs.setdefault('thscd1', 400)
    kwargs.setdefault('thscd2', 150)

    kwargs.setdefault('blksizev', 8)
    kwargs.setdefault('blksize', 8)
    kwargs.setdefault('pel', 2)

    output = dst or yuv_in

    def subdict(darg, knames):
        return {k: v for k, v in darg.items() if k in knames}

    def slice_args_and_call(fn, *args):
        return fn(*args, **subdict(kwargs, argspec(fn).args))

    def Rgb2Yuv(clip):
        kwargs = {
            'matrix_in_s': "rgb", 'matrix_s': "709",
            'format': vs.YUV420P8,
        }

        return core.resize.Bilinear(clip, **kwargs)

    super_clip = slice_args_and_call(core.mv.Super, yuv_in)
    vecs = slice_args_and_call(core.mv.Analyse, super_clip)

    thscd1, thscd2 = kwargs['thscd1'], kwargs['thscd2']
    kw = {'thscd1': thscd1, 'thscd2': thscd2}

    pads = {
        'bottom': 4 * kwargs['blksizev'],
        'right': 4 * kwargs['blksize'],
        'top': 4 * kwargs['blksizev'],
        'left': 4 * kwargs['blksize'],
    }

    AddBorders = core.std.AddBorders

    if 'global_motion' in kwargs:
        if 'mask' not in kwargs:
            y_in = core.std.ShufflePlanes(yuv_in, 0, vs.GRAY)
            darkmask = core.std.Expr(y_in, "x 40 > 255 *")

            darkmask = core.std.Crop(darkmask, **pads)
            darkmask = AddBorders(darkmask, **pads)
            kwargs['mask'] = darkmask

    hvecs = core.mv.Mask(yuv_in, vecs, kind=3, ysc=128, **kw)
    vvecs = core.mv.Mask(yuv_in, vecs, kind=4, ysc=128, **kw)

    if 'scd_delta' in kwargs:
        # TODO(ygitman): This is ugly, change
        kwargs['delta'] = kwargs['scd_delta']

    V = slice_args_and_call(core.mv.Analyse, super_clip) \
        if 'scd_delta' in kwargs else vecs

    # TODO(ygitman): do better job here
    output = core.mv.SCDetection(output, V, **kw)

    AD = core.mv.Mask(yuv_in, vecs, kind=1, **kw)

    ShufflePlanes = core.std.ShufflePlanes

    dx = ShufflePlanes(hvecs, 0, vs.GRAY)
    dy = ShufflePlanes(vvecs, 0, vs.GRAY)

    def xy2rgb(x, y):
        y = (y - 128.0) / kwargs['pel']
        x = (x - 128.0) / kwargs['pel']

        H = math.atan2(y, x) / (2.0 * math.pi) + 0.5
        V = min(math.sqrt(x * x + y * y) / 16, 1)
        return hsv_to_rgb(H, 1, V)

    def xy2r(x, y):
        return int(255 * xy2rgb(x, y)[0])

    def xy2g(x, y):
        return int(255 * xy2rgb(x, y)[1])

    def xy2b(x, y):
        return int(255 * xy2rgb(x, y)[2])

    R = core.std.Lut2(dx, dy, function=xy2r)
    G = core.std.Lut2(dx, dy, function=xy2g)
    B = core.std.Lut2(dx, dy, function=xy2b)

    if 'global_motion' in kwargs:
        output = slice_args_and_call(core.mv.DepanAnalyse, output, vecs)

    dx = core.std.Expr(dx, "x 128 - %d /" % kwargs['pel'], vs.GRAYS)
    dy = core.std.Expr(dy, "x 128 - %d /" % kwargs['pel'], vs.GRAYS)

    vis = core.std.ShufflePlanes([R, G, B], [0, 0, 0], vs.RGB)

    return output, [dx, dy, Rgb2Yuv(vis), ShufflePlanes(AD, 0, vs.GRAY)]


""" MNIST Tutorial (ConvNet)
This tutorial guides you through a classification task on MNIST dataset
by constructing and trainnig a ConvNet.
"""

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

def weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)

def conv2d(x, W):
    return tf.nn.conv2d(x, W, [1, 1, 1, 1], padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, [1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')

# read training data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# define input
x = tf.placeholder(tf.float32, shape=[None, 784])   # None tells TensorFlow that the dimension does not matter
x_image = tf.reshape(x, (-1, 28, 28, 1))            # the convention is TensorFlow is (b, h, w, c)

# build our network
# conv1 + relu + maxpool
W_conv1 = weight_variable([5, 5, 1, 32])            # the convention is (h, w, c_in, c_out)
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

# conv2 + relu + maxpool
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

# fc1 + relu
W_fc1 = weight_variable((7 * 7 * 64, 1024))
b_fc1 = bias_variable((1024,))

h_pool2_flat = tf.reshape(h_pool2, (-1, 7 * 7 * 64))
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)

# dropout (prevent over-fitting)
# set keep_prob as a input so we can disable dropout layer during testing
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

# read-out (fc2)
W_fc2 = weight_variable((1024, 10))
b_fc2 = bias_variable((10,))
y = tf.matmul(h_fc1_drop, W_fc2) + b_fc2

# cross-entropy loss
y_gt = tf.placeholder(tf.int32, shape=[None, 10])
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_gt, logits=y))
train = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)

# evaluation
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_gt, 1))
precision = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

# start trining
sess = tf.Session()
sess.run(tf.global_variables_initializer())

# summaries for tensor board
tf.summary.scalar('loss', cross_entropy)
tf.summary.scalar('precision', precision)
summary_op = tf.summary.merge_all()
summary_writer = tf.summary.FileWriter('tensor_logs', sess.graph)

for i in range(20000):
    batch = mnist.train.next_batch(50)

    _, summary = sess.run([train, summary_op], feed_dict={x: batch[0], y_gt: batch[1], keep_prob: 0.5})
    summary_writer.add_summary(summary, global_step=i)

# evaluating on test set
performance = sess.run(precision, feed_dict={x: mnist.test.images, y_gt: mnist.test.labels, keep_prob: 1.0})
print('precision on test set: {0}'.format(performance))


import math

def readable_time(inital):
	"""Turns the commands.OnCooldown.retry_after into a readable format for users"""
	days = 0
	hours = 0
	minutes = 0
	seconds = 0

	if inital > (60*60*24):
		days = int(math.floor(inital/(60*60*24)))
		inital -= days*(60*60*24)

	if inital > 3600:
		hours = int(math.floor(inital/3600))
		inital -= hours*3600

	if inital > 60:
		minutes = int(math.floor(inital/60))
		inital -= minutes*60

	if inital > 0:
		seconds = inital
		inital -= seconds

	if days == 0:
		if hours == 0:
			if minutes == 0:
				return f'{seconds} second(s)'
			return f'{minutes} minute(s), {seconds} second(s)'
		return f'{hours} hour(s), {minutes} minute(s), {seconds} second(s)'
	else:
		return f"{days} day(s), {hours} hour(s), {minutes} minute(s), {seconds} second(s)"


from celery import Celery
import subprocess
import json
# Celery configuration
#-->Rabbit(hostname) in container
CELERY_BROKER_URL =['amqp://rabbitmq:rabbitmq@rabbit:5672/','amqp://rabbitmq:rabbitmq@130.238.28.112:5672/','amqp://rabbitmq:rabbitmq@localhost:5672/']

CELERY_RESULT_BACKEND = 'rpc://'
#Add MongoDB
#CELERY RESULT BACKEND = ’mongodb:password//130.238.28.112:27017'

# Initialize Celery
app = Celery('celery', broker=CELERY_BROKER_URL, backend=CELERY_RESULT_BACKEND)

@app.task
def startSimulation(filename,input_path):
    #get path for filename and corresponding .xml file
    xmlfilename = input_path + filename.split(".")[0]+".xml"
    filename_path = input_path + filename

    #Task 1 convert msh to xml by dolfin-convert <msh> <xml>
    #!dolfin-convert $filename_path $xmlfilename
    subprocess.run(["dolfin-convert", filename_path, xmlfilename],check=True)
    #Task 2 run navier_stokes_solver by ./airfoil 10 0.0001 10. 1 file
    #! ../murtazo/navier_stokes_solver/airfoil 10 0.00001 10. 1 $xmlfilename
    subprocess.run(["../murtazo/navier_stokes_solver/airfoil", "10","0.0001","10.","1", xmlfilename],check=True)
    #Task3 getResults by Tail –n 1 drag_ligt.m
    #output = !tail -n 1  ../murtazo/navier_stokes_solver/results/drag_ligt.m
    output =  subprocess.run(["tail", "-n","1", "./results/drag_ligt.m"],check=True, stdout=subprocess.PIPE, universal_newlines=True)
    result = {"filename": filename, "lift": output.stdout.split("\t")[1], "drag":output.stdout.split("\t")[2].split("\\n")[0]}
    return json.dumps(result)

if __name__ == '__main__':
    app.start()


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

from five import grok

from collective.elections.election import IElection

from Products.CMFCore.utils import getToolByName

from datetime import datetime

class CanSubmitToPublic(grok.View):
    grok.context(IElection)
    grok.name("can-submit-to-public")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        pm = getToolByName(self.context, 'portal_membership')

        auth_member = pm.getAuthenticatedMember()
        ceo = self.context.chief_electoral_officer

        proper_user = auth_member.getMemberId() == ceo

        if not proper_user:
            return False

        if not (getattr(self.context, 'configuration_pdf') and
                getattr(self.context, 'configuration_pdf_signature')):
            return False

        return True

    def render(self):
        return "can-submit-to-public"

class CanSelectNominees(grok.View):
    grok.context(IElection)
    grok.name("can-select-nominees")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        nsd = self.context.nominee_selection_date

        if nsd:
            now = datetime.now()
            return now > nsd
        else:
            return False

    def render(self):
        return "can-select-nominees"

class CanSendToPublic(grok.View):
    grok.context(IElection)
    grok.name("can-send-to-public")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        pm = getToolByName(self.context, 'portal_membership')

        auth_member = pm.getAuthenticatedMember()
        ceo = self.context.chief_electoral_officer

        proper_user = auth_member.getMemberId() == ceo

        if not proper_user:
            return False

        if not (getattr(self.context, 'rolls_pdf') and
                getattr(self.context, 'rolls_pdf_signature')):
            return False

        return True

    def render(self):
        return "can-send-to-public"

class CanBeStarted(grok.View):
    grok.context(IElection)
    grok.name("can-be-started")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        vsd = self.context.voting_start_date
        now = datetime.now()

        return now > vsd

    def render(self):
        return "can-be-started"

class ShouldBeEnded(grok.View):
    grok.context(IElection)
    grok.name("should-be-ended")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        ved = self.context.voting_end_date
        now = datetime.now()

        return now > ved

    def render(self):
        return "should-be-ended"

class ResultsShouldGoPublic(grok.View):
    grok.context(IElection)
    grok.name("results-should-be-public")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        pd = self.context.publication_date
        now = datetime.now()

        return now > pd

    def render(self):
        return "results-should-be-public"

class CanBeClosed(grok.View):
    grok.context(IElection)
    grok.name("can-be-closed")
    grok.require("cmf.ReviewPortalContent")

    def __call__(self):
        pm = getToolByName(self.context, 'portal_membership')

        auth_member = pm.getAuthenticatedMember()
        ceo = self.context.chief_electoral_officer

        proper_user = auth_member.getMemberId() == ceo

        if not proper_user:
            return False

        return True

    def render(self):
        return "can-be-closed"


def solution(s):
  answer = [-1]

  for i in range(1, len(s)):
    str = s[0: i]
    for j in range(len(str) - 1, -1, -1):
      if (str[j] == s[i]):
        answer.append(i - j)
        break
    if (len(answer) != i + 1):
      answer.append(-1)

  return answer

print(solution('foobar'))

python 문법 연습/가장 가까운 같은 글자.py

가장 가까운 같은 글자.py


# -*- coding: utf-8 -*-
import geopandas as gpd
import pandas as pd
from utils.to_mercator import to_mercator
from config.static_vars import *

def road_dens_cal(raw_road: gpd.GeoDataFrame, block: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
    """路网密度计算

    Args:
        raw_road (gpd.GeoDataFrame): 路网gdf
        block (gpd.GeoDataFrame): 地块gdf

    Returns:
        gdf
    """
    ori_crs = block.crs
    cols = block.columns.to_list()
    to_mercator(raw_road)
    to_mercator(block)
    block['block_area'] = block.area
    block['join_id'] = block.index

    overlap = gpd.overlay(raw_road, block)[['join_id', 'geometry']]
    overlap['road_len'] = overlap.length
    len = overlap.groupby(['join_id']).sum()[['road_len']]
    res = pd.merge(block, len, how='outer',
                   left_on='join_id', right_index=True)
    res['road_len_sum'] = res['road_len'].fillna(
        0).astype('float').round(2)
    res['road_density'] = (res['road_len_sum'] / 1000) / \
        (res['block_area']/1000000)
    res = res.to_crs(ori_crs)[cols+['road_density']]
    return res


# from abc import abstractproperty

# 1 2 3 4 5  k = 2

# 4 5 1 2 3
# first reverse the array
# 5 4 3 2 1
# and reverse the k first elements and reverse the remaining part.
# 4 5 1 2 3

# The helper function reverses the array based on the list, start and end value provided.So,each time we call the helper function with
# different start, end .
# Also repeating 6 times is same as repeating 1 times so if k is greater than len(list) then we find the remainder and update the k.

def helper_function(list,start, end):
  while start < end:
    temp = list[start]
    list[start] = list[end]
    list[end] = temp
    start += 1
    end -= 1

def rotate(list,k):
  if k > len(list):
    k = k % len(list)
  start = 0
  end = len(list) - 1
  helper_function(list,start,end)

  start = 0
  end = k - 1
  helper_function(list,start,end)

  start = k
  end = len(list)-1
  helper_function(list,start,end)
  return(list)

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

def rotatesinglearray(list):
  #only rotating the array by 1.
  temp = list[0]
  count = list[1]
  for i in range(0,len(list)-2):
    #  if i == len(list) - 2:
    #    count == list[len(list)-1] # last element
    #  if i == len(list) - 1:
    #   list[0] = count
      #return list
    list[i+1] = temp
    temp = count
    count = list[i+2]
  #print(i)
  print(temp)
  print(count)
  list[len(list)-1] = temp
  list[0] =count
  return list
#print(rotatesinglearray([1,2,3,4,5,6,7,8]))

# using an additional space.just create a array with all zero and place all the other elements
# from the array in respective postions.
def rotate_array(list):
  value = len(list)
  two_list = []
  for element in range(0, len(list)):
    value = []
    for result in range(0,len(list)):
      value.append(0)
    two_list.append(value)

  for element in range(0,len(list)):
    for value in range(0,len(list)):
      two_list[element][value] = list[len(list)-1-value][element]
  return two_list

#print(two_array([[1,2,3],[4,5,6],[7,8,9]]))
# TIme complexity = 0(M * N) where M is the number of rows and N is the no of columns.
#space complexity = o(M * N) Where M is the number of rows and N is the number of columns.

# Also can be said Time complexity  as O(N) where N is the total no of elements in the list.

# Pattern -- 00 -- 30
#            01 -- 20
#            02 -- 10
#            03 -- 00
#            ie [element][value] = [len(list)-1-value][element]
#In place solutions.
#   1 2 3      1 4 7     7 4 1
#   4 5 6      2 5 8 --  8 5 2
#   7 8 9   -- 3 6 9     9 6 3
#   First transposing the matrix and then swapping the elements until we reach the middle of matrix.
# Transposing. matrix[i][j] = matrix [j][i]
def rotatearray(matrix):
  for row in range(0, len(matrix)):
    #print(str(row) + "i am row")
    for col in range(row,len(matrix)):
      #This loop should start from row. if starts from 0 then double swapping will occur and
      #we will not be able to swap becuase we just want to swap them once.NOt twice.

      #print(str(col) + "i am column")
      temp = matrix[row][col]

      matrix[row][col] = matrix[col][row]
      matrix[col][row] = temp

  #swapping the matrix so that it gets rotated.
  # pattern for swapping.
  # after transposing the matrix we get:
  # let us suppose we have 4*4 matrix so
  # original =
  # 1 2   3   4
  # 5 6   7   8
  # 9 10 11  12
  # 13 14 15 15
  # after tranposing it becomes:

  # 1 5 9  13
  # 2 6 10 14
  # 3 7 11 15
  # 4 8 12 16
  # now we see that if we are just able to swap first and last and 2nd and 2nd last in row,the
  # matrix is resulted so.len(matrix)//2 is done because we just want to swap the row up to half
  for row in range(0, int(len(matrix)/2)):
    for col in range(0, len(matrix)):
      temp = matrix[col][row]
      matrix[col][row] = matrix[col][len(matrix)-1-row]
      matrix[col][len(matrix)-1-row] = temp
  return matrix

#print(rotatearray([[1]]))


T = int(input())
for testcase in range(1,T+1):
    t,length = input().split()
    arr = list(input().split())
    ans = []
    num = ['ZRO','ONE','TWO','THR','FOR','FIV','SIX','SVN','EGT','NIN']
    for i in range(len(num)):
        for j in range(len(arr)):
            if num[i] == arr[j]:
                ans.append(arr[j])
    print(f'#{testcase}')
    print(*ans)

T = int(input())

for tc in range(1, T+1):
    t, case_number = input().split()
    case_number = int(case_number)
    arr = list(input().split())

    names = ["ZRO", "ONE", "TWO", "THR", "FOR", "FIV", "SIX", "SVN", "EGT", "NIN"]
    ans = []
    for a in range(len(names)):
        for i in range(len(arr)):
            if names[a] == arr[i]:
                ans.append(arr[i])

    print(f'#{tc}')
    for j in range(len(ans)):
        print(ans[j], end= ' ')


'''
Drill Description:
For this drill, you will need to write a script that creates a GUI with
a button widget and a text widget. Your script will also include a function
that when it is called will invoke a dialog modal which will allow users
with the ability to select a folder directory from their system. Finally,
your script will show the user’s selected directory path into the text field.

Requirements:
Your script will need to use Python 3 and the Tkinter module.

Your script will need to use the askdirectory() method from the Tkinter module.

Your script will need have a function linked to the button widget so that
once the button has been clicked will take the user’s selected file path
retained by the askdirectory() method and print it within your GUI’s text widget.
'''

from tkinter import *
import tkinter

class ParentWindow (Frame):
    def __init__ ():
        Frame.__init__ ()

        resizable(width=False, height=False)
        geometry('{}x{}'.format(525,210))
        title('Browse')

#browse button1
        btn_browse = Button(root, width=12, height=1, text="Browse...", command=func_browse)
        btn_browse.grid(row=1, column=0, padx=(20,0), pady=(50,0))

    def func_browse():
        filename = filedialog.askopenfilename()
        pathlabel.config(text=filename)

if __name__ == "__main__":
    root = Tk()
#    App = ParentWindow(root)
    root.mainloop


from rest_framework import serializers
from users_exam.models import UsersExam
from student_answer.models import StudentAnswer
from test_question.models import TestQuestion
import numpy as np

class UsersExamAPISerializer(serializers.ModelSerializer):
    def create(self, validated_data):
        if not UsersExam.objects.filter(user=self.context['request'].user).exists():
            user = UsersExam.objects.create(user=self.context['request'].user, exam=validated_data['exam'])
        else:
            UsersExam.objects.filter(user=self.context['request'].user).update(exam=validated_data['exam'])
            user = UsersExam.objects.get(user=self.context['request'].user)
            StudentAnswer.objects.filter(user=self.context['request'].user).delete()
        q_read = TestQuestion.objects.filter(is_reading=True)
        q_not_read = TestQuestion.objects.filter(is_reading=False)
        total = len(q_read) + len(q_not_read)
        not_read_order = np.random.permutation(range(len(q_read) + 1, total + 1))

        read_order = np.random.permutation(range(1, len(q_read) + 1))
        for i in range(len(read_order)):
            StudentAnswer.objects.create(number=read_order[i],
                                         user=self.context['request'].user, question=q_read[i])

        for i in range(len(not_read_order)):
            StudentAnswer.objects.create(number=not_read_order[i],
                                         user=self.context['request'].user, question=q_not_read[i])

        return user

    class Meta:
        model = UsersExam
        fields = [
            'exam',
        ]
        read_only_fields = ['user',]

class UsersExamSerializer(serializers.ModelSerializer):
    def update(self, instance, validated_data):
        instance.start = validated_data.get('start', instance.start)
        instance.finish = validated_data.get('finish', instance.finish)
        instance.save()
        return instance

    class Meta:
        model = UsersExam
        fields = [
            'user',
            'exam',
        ]


import numpy as np
from enum import Enum

#Bangkok
class Phase(Enum):
    E = [1]
    N_R = [2]
    SL = [3]
    WL = [4]
    S_R = [5]
    N_L = [6]
    R = [] # ???
    N_LN_R = N_L + N_R
    SLS_R = SL + S_R

#Texas
'''class Phase(Enum):
    W_L = [1]
    E = [2]
    N_L = [3]
    S = [4]
    E_L = [5]
    W = [6]
    S_L = [7]
    N = [8]
    R = []
    WW_L = W + W_L
    EE_L = E + E_L
    NN_L = N + N_L
    SS_L = S + S_L'''

# 1 Duplicate action is created when iterating over permissive left phases, purge them
def check_unique_action(action_sets, new_action_set):
    for action_set in action_sets:
        if new_action_set == action_set:
            return False
    return True

def get_all_actions(ew_upper_ring, ew_lower_ring, ns_upper_ring, ns_lower_ring):
    actions = []
    action_sets = []
    for upper in ew_upper_ring:
        for lower in ew_lower_ring:
            set_value = set(upper.value + lower.value)
            if check_unique_action(action_sets, set_value):
                action_sets.append(set_value)
                actions.append([upper, lower])
    for upper in ns_upper_ring:
        for lower in ns_lower_ring:
            set_value = set(upper.value + lower.value)
            if check_unique_action(action_sets, set_value):
                action_sets.append(set_value)
                actions.append([upper, lower])
    print(actions)
    return np.asarray(actions)

#Bangkok
ew_upper_ring = [Phase.E]
ew_lower_ring = [Phase.WL]
ns_upper_ring = [Phase.N_LN_R, Phase.N_L, Phase.S_R]
ns_lower_ring = [Phase.SLS_R, Phase.SL, Phase.N_R]

#Texas
'''ew_upper_ring = [Phase.E, Phase.W_L]
ew_lower_ring = [Phase.W, Phase.E_L]
ns_upper_ring = [Phase.NN_L, Phase.N, Phase.S_L]
ns_lower_ring = [Phase.SS_L, Phase.S, Phase.N_L]'''

get_all_actions(ew_upper_ring, ew_lower_ring, ns_upper_ring, ns_lower_ring)


from zad1testy import runtests
from math import inf

def minimum_distance(d, n, v, processed):  # funkcja szuka minimalnego dystansu
    ind = None, None
    minimum = inf
    for i in range(n):
        for j in range(3):
            if not processed[i][j] and d[i][j] != inf and minimum > d[i][j] and i != v:
                minimum = d[i][j]
                ind = i, j
    return ind[0], ind[1]

def dijkstra(G, v):
    n = len(G)
    d = [[inf, inf, inf] for _ in range(n)]
    d[v][0] = 0  # koncowy minimalny dystans
    d[v][1] = 0
    d[v][2] = 0
    processed = [[False, False, False] for _ in range(n)]  # wierzchołki przetworzone
    ind = 0

    while v is not None:
        if not processed[v][ind]:  # sprawdzam tylko nieprzetworzone wierzchołki, to poprawia wydajnosc
            for i in range(n):
                for j in range(3):
                    if G[v][i] != 0 and d[i][j] > d[v][j] + G[v][i] and ind != j:  # relaksacja, musze zmienic srodek transportu
                        d[i][j] = d[v][j] + G[v][i]
                processed[v][ind] = True

        v, ind = minimum_distance(d, n, v, processed)

    return d

def islands(G, A, B):
    d = dijkstra(G, A)
    if d[B] == inf:
        return None
    else:
        return min(d[B])

runtests(islands)


from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
from django.core.exceptions import ValidationError
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

from ordered_model.models import OrderedModel

from ..constants import RoleTypeChoices
from .managers import UserManager

class User(AbstractBaseUser, PermissionsMixin):
    """
    Use the built-in user model.
    """

    username = models.CharField(
        _("username"),
        max_length=150,
        unique=True,
        help_text=_("Required. 150 characters or fewer."),
        error_messages={"unique": _("A user with that username already exists.")},
    )
    first_name = models.CharField(_("first name"), max_length=255, blank=True)
    last_name = models.CharField(_("last name"), max_length=255, blank=True)
    email = models.EmailField(_("email address"), unique=True)
    is_staff = models.BooleanField(
        _("staff status"),
        default=False,
        help_text=_("Designates whether the user can log into this admin site."),
    )
    is_active = models.BooleanField(
        _("active"),
        default=True,
        help_text=_(
            "Designates whether this user should be treated as active. "
            "Unselect this instead of deleting accounts."
        ),
    )
    date_joined = models.DateTimeField(_("date joined"), default=timezone.now)
    role = models.ForeignKey(
        "accounts.Role",
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        verbose_name=_("role"),
    )

    objects = UserManager()

    USERNAME_FIELD = "username"
    REQUIRED_FIELDS = ["email"]

    class Meta:
        verbose_name = _("user")
        verbose_name_plural = _("users")

    def get_full_name(self):
        """
        Returns the first_name plus the last_name, with a space in between.
        """
        full_name = "%s %s" % (self.first_name, self.last_name)
        return full_name.strip()

    def get_short_name(self):
        """Returns the short name for the user."""
        return self.first_name

    def as_reviewer_display(self) -> str:
        name = self.get_full_name() or self.email or self.username
        return _("{name} ({role})").format(name=name, role=self.role.name)

class Role(OrderedModel):
    name = models.CharField(
        _("name"), max_length=255, unique=True, help_text=_("Name of the role")
    )
    type = models.CharField(
        _("type"),
        max_length=255,
        help_text=_("The type of role"),
        choices=RoleTypeChoices,
        default=RoleTypeChoices.record_manager,
    )
    organisatie_onderdeel = models.URLField(_("organisatie onderdeel"), blank=True)
    can_start_destruction = models.BooleanField(
        _("can start destruction"),
        default=False,
        help_text=_(
            'Designates whether people in this role can create a "vernietigingslijst", which is the '
            'starting point for the "records destruction" process.'
        ),
    )
    can_review_destruction = models.BooleanField(
        _("can review destruction"),
        default=False,
        help_text=_(
            "Designates if people in this role can review created record destruction lists and approve/reject them."
        ),
    )
    can_view_case_details = models.BooleanField(
        _("can view case details"),
        default=False,
        help_text=_(
            "Designates whether people in this role can view the contents of zaken listed on the "
            "record destruction lists."
        ),
    )

    class Meta(OrderedModel.Meta):
        verbose_name = _("role")
        verbose_name_plural = _("roles")

    def __str__(self):
        return self.name

    def clean(self):
        if self.type == RoleTypeChoices.archivist:
            if not self.can_review_destruction:
                raise ValidationError(
                    {
                        "can_review_destruction": _(
                            "The archivist needs to at least have the permission to review a destruction list."
                        )
                    }
                )
        elif self.type == RoleTypeChoices.record_manager:
            if not self.can_start_destruction or not self.can_view_case_details:
                error_message = _(
                    "The record manager needs to at least have the permission "
                    "to start a destruction list and to view the details of a case."
                )
                raise ValidationError(
                    {
                        "can_start_destruction": error_message,
                        "can_view_case_details": error_message,
                    }
                )
        elif self.type == RoleTypeChoices.process_owner:
            if not self.can_review_destruction or not self.can_view_case_details:
                error_message = _(
                    "The process owner needs to at least have the permission "
                    "to review a destruction list and to view the details of a case."
                )
                raise ValidationError(
                    {
                        "can_review_destruction": error_message,
                        "can_view_case_details": error_message,
                    }
                )
        elif self.type == RoleTypeChoices.functional_admin:
            if (
                not self.can_review_destruction
                or not self.can_view_case_details
                or not self.can_start_destruction
            ):
                error_message = _(
                    "The functional administrator should have all the permissions."
                )
                raise ValidationError(
                    {
                        "can_review_destruction": error_message,
                        "can_view_case_details": error_message,
                        "can_start_destruction": error_message,
                    }
                )


from sklearn.model_selection import LeaveOneOut
from sklearn import svm
from rdkit import Chem
import numpy as np
import os
import pandas as pd

# import data
datadir = "/Users/yihyun/Code/"
prism_both = pd.read_csv(os.path.join(datadir, "drug_sensitivity_prediction/0.data/processed/prism_disjoint_test.csv"), index_col='smiles')
prism_train = pd.read_csv(os.path.join(datadir, "drug_sensitivity_prediction/0.data/processed/prism_train.csv"), index_col='smiles')
pred_df = pd.read_csv(os.path.join(datadir, "drug_sensitivity_prediction/2.Combined_model_evaluation/2_1.CaDRReS_CLsim/prediction/CaDRReS_CLsim_cellblind_pred.csv"), index_col='smiles')
test_cl = prism_both.columns.to_list()

loo = LeaveOneOut()
# convert smiles encoding to fingerprints
train_mol = prism_train.index.tolist()
train_mol_rdkit = list(map(Chem.MolFromSmiles,train_mol))
train_fps = [list(map(int, list(Chem.RDKFingerprint(x).ToBitString()))) for x in train_mol_rdkit]
train_fps = np.array(train_fps)

# evaluation result
result = np.empty((len(train_mol), len(test_cl)))
result[:] = np.nan
result_df = pd.DataFrame(result, columns=test_cl, index = train_mol)

for cell_line in test_cl:
     #cell_line = test_cl[0]
     cadrres_pred = pred_df.loc[test_cl].T

     train_auc = np.array([auc if auc>=0 else 0 for auc in cadrres_pred[cell_line]])

     for i, (train_index, test_index) in enumerate(loo.split(train_fps)):
          print(f"Fold {i}:")
          # svm model fitting
          X = train_fps[train_index,:]
          y = train_auc[train_index]
          model = svm.SVR()
          model.fit(X, y)

          test_fps = train_fps[test_index,:]
          pred_y = model.predict(test_fps)
          result_df.loc[np.array(train_mol)[test_index], cell_line] = pred_y

result_df.to_csv(os.path.join(datadir, "drug_sensitivity_prediction/2.Combined_model_evaluation/2_2.CaDRReS_CLsim_SVM/prediction/CaDRReS_SVM_LOO_cellblind_pred.csv"), index = True)


import pandas as pd
import numpy as np
from IPython.display import display, Markdown

def make_df_we_wanted(df, dummie_col = "DepartmentDescription", is_use_positive_scancount_only = True, is_test_df = False):
    result = df.copy()

    # 요일을 숫자로 변경
    result["Weekday"] = __change_weekday_to_number(result)

    # 반환여부를 1(반환한 경우), 0로 표현
    result["Return"] = result["ScanCount"].apply(lambda a: 1 if a < 0 else 0)

    # Scan
    if is_use_positive_scancount_only:
        result["ScanCount"] = result["ScanCount"].apply(lambda a : a if a >=0 else 0)

    # 원하는 컬럼(dummie_col에 넣어준 컬럼명)을 Dummie로 변경
    result = __make_dummy_columns(result, dummie_col)

    # VisitNumber를 이용해서 groupby하여 Row수를 VisitNumber Unique한 숫자만큼 축소
    result = __make_df_groupby_visit_number(result, is_test_df)

    return __make_weekday_as_dummies(result)

def __change_weekday_to_number(df):
    weekday_dict = {
        "Monday" : 1,
        "Tuesday" : 2,
        "Wednesday" : 3,
        "Thursday" : 4,
        "Friday" : 5,
        "Saturday" : 6,
        "Sunday" : 7
    }
    return df["Weekday"].map(weekday_dict)

def __make_dummy_columns(df, dummie_col):
    ItemNumber = df["ScanCount"]
    dummies_desc = pd.get_dummies(df[dummie_col])
    desc_cols = dummies_desc.columns
    df[desc_cols] = dummies_desc.apply(lambda x: x * ItemNumber)
    should_remove_cols = ["Upc", "DepartmentDescription", "FinelineNumber", "ScanCount"]
    new_cols = [col for col in df.columns if col not in should_remove_cols]
    return df[new_cols]

def __make_df_groupby_visit_number(df, is_test_df):
    cols = [col for col in list(df.columns) if col != "VisitNumber"]
    np_max_cols = cols[:2] if is_test_df else cols[:3]
    values = [np.max if col in np_max_cols else np.sum for col in cols]
    dict_ = dict(zip(cols, values))
    if is_test_df:
        result_df = df.groupby(by='VisitNumber').agg(dict_).reset_index()
        result_df["HEALTH AND BEAUTY AIDS"] = np.zeros(len(result_df))
        return result_df
    return df.groupby(by='VisitNumber').agg(dict_).reset_index()

def __make_weekday_as_dummies(df):
    dummies_desc = pd.get_dummies(df["Weekday"])
    desc_cols = dummies_desc.columns
    df[desc_cols] = dummies_desc
    return df.drop("Weekday", axis = 1)


from setuptools import setup

__version__ = "0.6.3"

setup(name='schemas',
      version=__version__,
      description='Python library for marshalling and validation',
      author='Charles Reese',
      author_email='charlespreese@gmail.com',
      url='https://github.com/creese/schemas',
      download_url=(
          'https://github.com/creese/schemas/archive/' + __version__ + '.zip'),
      packages=['schemas'],
      install_requires=['functions',
                        'pytest'],)


import tensorflow as tf

class GRU:
    """Implementation of a Gated Recurrent Unit (GRU) as described in [1].

    [1] Chung, J., Gulcehre, C., Cho, K., & Bengio, Y. (2014). Empirical evaluation of gated recurrent neural networks on sequence modeling. arXiv preprint arXiv:1412.3555.

    Arguments
    ---------
    input_dimensions: int
        The size of the input vectors (x_t).
    hidden_size: int
        The size of the hidden layer vectors (h_t).
    dtype: obj
        The datatype used for the variables and constants (optional).
    """

    def __init__(self, input_dimensions, hidden_size, dtype=tf.float64):
        self.input_dimensions = input_dimensions
        self.hidden_size = hidden_size

        # Weights for input vectors of shape (input_dimensions, hidden_size)
        self.Wr = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.input_dimensions, self.hidden_size), mean=0, stddev=0.01), name='Wr')
        self.Wz = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.input_dimensions, self.hidden_size), mean=0, stddev=0.01), name='Wz')
        self.Wh = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.input_dimensions, self.hidden_size), mean=0, stddev=0.01), name='Wh')

        # Weights for hidden vectors of shape (hidden_size, hidden_size)
        self.Ur = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.hidden_size, self.hidden_size), mean=0, stddev=0.01), name='Ur')
        self.Uz = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.hidden_size, self.hidden_size), mean=0, stddev=0.01), name='Uz')
        self.Uh = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.hidden_size, self.hidden_size), mean=0, stddev=0.01), name='Uh')

        # Biases for hidden vectors of shape (hidden_size,)
        self.br = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.hidden_size,), mean=0, stddev=0.01), name='br')
        self.bz = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.hidden_size,), mean=0, stddev=0.01), name='bz')
        self.bh = tf.Variable(tf.truncated_normal(dtype=dtype, shape=(self.hidden_size,), mean=0, stddev=0.01), name='bh')

        # Define the input layer placeholder
        self.input_layer = tf.placeholder(dtype=tf.float64, shape=(None, None, input_dimensions), name='input')

        # Put the time-dimension upfront for the scan operator
        self.x_t = tf.transpose(self.input_layer, [1, 0, 2], name='x_t')

        # A little hack (to obtain the same shape as the input matrix) to define the initial hidden state h_0
        self.h_0 = tf.matmul(self.x_t[0, :, :], tf.zeros(dtype=tf.float64, shape=(input_dimensions, hidden_size)), name='h_0')

        # Perform the scan operator
        self.h_t_transposed = tf.scan(self.forward_pass, self.x_t, initializer=self.h_0, name='h_t_transposed')

        # Transpose the result back
        self.h_t = tf.transpose(self.h_t_transposed, [1, 0, 2], name='h_t')

    def forward_pass(self, h_tm1, x_t):
        """Perform a forward pass.

        Arguments
        ---------
        h_tm1: np.matrix
            The hidden state at the previous timestep (h_{t-1}).
        x_t: np.matrix
            The input vector.
        """
        # Definitions of z_t and r_t
        z_t = tf.sigmoid(tf.matmul(x_t, self.Wz) + tf.matmul(h_tm1, self.Uz) + self.bz)
        r_t = tf.sigmoid(tf.matmul(x_t, self.Wr) + tf.matmul(h_tm1, self.Ur) + self.br)

        # Definition of h~_t
        h_proposal = tf.tanh(tf.matmul(x_t, self.Wh) + tf.matmul(tf.multiply(r_t, h_tm1), self.Uh) + self.bh)

        # Compute the next hidden state
        h_t = tf.multiply(1 - z_t, h_tm1) + tf.multiply(z_t, h_proposal)

        return h_t

#%% (3) Initialize and train the model.

# The input has 2 dimensions: dimension 0 is reserved for the first term and dimension 1 is reverved for the second term
input_dimensions = 2

# Arbitrary number for the size of the hidden state
hidden_size = 16

# Initialize a session
session = tf.Session()

# Create a new instance of the GRU model
gru = GRU(input_dimensions, hidden_size)

# Add an additional layer on top of each of the hidden state outputs
W_output = tf.Variable(tf.truncated_normal(dtype=tf.float64, shape=(hidden_size, 1), mean=0, stddev=0.01))
b_output = tf.Variable(tf.truncated_normal(dtype=tf.float64, shape=(1,), mean=0, stddev=0.01))
output = tf.map_fn(lambda h_t: tf.matmul(h_t, W_output) + b_output, gru.h_t)

# Create a placeholder for the expected output
expected_output = tf.placeholder(dtype=tf.float64, shape=(batch_size, time_size, 1), name='expected_output')

# Just use quadratic loss
loss = tf.reduce_sum(0.5 * tf.pow(output - expected_output, 2)) / float(batch_size)

# Use the Adam optimizer for training
train_step = tf.train.AdamOptimizer().minimize(loss)

# Initialize all the variables
init_variables = tf.global_variables_initializer()
session.run(init_variables)

# Initialize the losses
train_losses = []
validation_losses = []

# Perform all the iterations
for epoch in range(5000):
    # Compute the losses
    _, train_loss = session.run([train_step, loss], feed_dict={gru.input_layer: X_train, expected_output: Y_train})
    validation_loss = session.run(loss, feed_dict={gru.input_layer: X_test, expected_output: Y_test})

    # Log the losses
    train_losses += [train_loss]
    validation_losses += [validation_loss]

    # Display an update every 50 iterations
    if epoch % 50 == 0:
        plt.plot(train_losses, '-b', label='Train loss')
        plt.plot(validation_losses, '-r', label='Validation loss')
        plt.legend(loc=0)
        plt.title('Loss')
        plt.xlabel('Iteration')
        plt.ylabel('Loss')
        plt.show()
        print('Iteration: %d, train loss: %.4f, test loss: %.4f' % (epoch, train_loss, validation_loss))


from odoo import models
from odoo.addons.account.models.chart_template import template

class AccountChartTemplate(models.AbstractModel):
    _inherit = 'account.chart.template'

    @template('tr')
    def _get_tr_template_data(self):
        return {
            'property_account_receivable_id': 'tr120',
            'property_account_payable_id': 'tr320',
            'property_account_expense_categ_id': 'tr150',
            'property_account_income_categ_id': 'tr600',
            'code_digits': '6',
        }

    @template('tr', 'res.company')
    def _get_tr_res_company(self):
        return {
            self.env.company.id: {
                'account_fiscal_country_id': 'base.tr',
                'bank_account_code_prefix': '102',
                'cash_account_code_prefix': '100',
                'transfer_account_code_prefix': '103',
                'account_default_pos_receivable_account_id': 'tr123',
                'income_currency_exchange_account_id': 'tr646',
                'expense_currency_exchange_account_id': 'tr656',
                'account_journal_suspense_account_id': 'tr102999',
                'account_journal_payment_debit_account_id': 'tr102997',
                'account_journal_payment_credit_account_id': 'tr102998',
                'account_sale_tax_id': 'tr_kdv_satis_sale_20',
                'account_purchase_tax_id': 'tr_kdv_satis_purchase_20',
            },
        }


from heapq import *

def find_k_largest_numbers(nums, k):
  minHeap = []
  # put first 'K' numbers in the min heap
  for i in range(k):
    heappush(minHeap, nums[i])

  # go through the remaining numbers of the array, if the number from the array is bigger than the
  # top(smallest) number of the min-heap, remove the top number from heap and add the number from array
  for i in range(k, len(nums)):
    if nums[i] > minHeap[0]:
      heappop(minHeap)
      heappush(minHeap, nums[i])

  # the heap has the top 'K' numbers, return them in a list
  return list(minHeap)

def main():

  print("Here are the top K numbers: " +
        str(find_k_largest_numbers([3, 1, 5, 12, 2, 11], 3)))

  print("Here are the top K numbers: " +
        str(find_k_largest_numbers([5, 12, 11, -1, 12], 3)))

main()

from heapq import *

def find_Kth_smallest_number(nums, k):
  maxHeap = []
  # put first k numbers in the max heap
  for i in range(k):
    heappush(maxHeap, -nums[i])

  # go through the remaining numbers of the array, if the number from the array is smaller than the
  # top(biggest) number of the heap, remove the top number from heap and add the number from array
  for i in range(k, len(nums)):
    if -nums[i] > maxHeap[0]:
      heappop(maxHeap)
      heappush(maxHeap, -nums[i])

  # the root of the heap has the Kth smallest number
  return -maxHeap[0]

def main():

  print("Kth smallest number is: " +
        str(find_Kth_smallest_number([1, 5, 12, 2, 11, 5], 3)))

  # since there are two 5s in the input array, our 3rd and 4th smallest numbers should be a '5'
  print("Kth smallest number is: " +
        str(find_Kth_smallest_number([1, 5, 12, 2, 11, 5], 4)))

  print("Kth smallest number is: " +
        str(find_Kth_smallest_number([5, 12, 11, -1, 12], 3)))

main()

from __future__ import print_function
from heapq import *

class Point:

  def __init__(self, x, y):
    self.x = x
    self.y = y

  # used for max-heap
  def __lt__(self, other):
    return self.distance_from_origin() > other.distance_from_origin()

  def distance_from_origin(self):
    # ignoring sqrt to calculate the distance
    return (self.x * self.x) + (self.y * self.y)

  def print_point(self):
    print("[" + str(self.x) + ", " + str(self.y) + "] ", end='')

def find_closest_points(points, k):
  maxHeap = []
  # put first 'k' points in the max heap
  for i in range(k):
    heappush(maxHeap, points[i])

  # go through the remaining points of the input array, if a point is closer to the origin than the top point
  # of the max-heap, remove the top point from heap and add the point from the input array
  for i in range(k, len(points)):
    if points[i].distance_from_origin() < maxHeap[0].distance_from_origin():
      heappop(maxHeap)
      heappush(maxHeap, points[i])

  # the heap has 'k' points closest to the origin, return them in a list
  return list(maxHeap)

def main():

  result = find_closest_points([Point(1, 3), Point(3, 4), Point(2, -1)], 2)
  print("Here are the k points closest the origin: ", end='')
  for point in result:
    point.print_point()

main()

from heapq import *

def minimum_cost_to_connect_ropes(ropeLengths):
  minHeap = []
  # add all ropes to the min heap
  for i in ropeLengths:
    heappush(minHeap, i)

  # go through the values of the heap, in each step take top (lowest) rope lengths from the min heap
  # connect them and push the result back to the min heap.
  # keep doing this until the heap is left with only one rope
  result, temp = 0, 0
  while len(minHeap) > 1:
    temp = heappop(minHeap) + heappop(minHeap)
    result += temp
    heappush(minHeap, temp)

  return result

def main():

  print("Minimum cost to connect ropes: " +
        str(minimum_cost_to_connect_ropes([1, 3, 11, 5])))
  print("Minimum cost to connect ropes: " +
        str(minimum_cost_to_connect_ropes([3, 4, 5, 6])))
  print("Minimum cost to connect ropes: " +
        str(minimum_cost_to_connect_ropes([1, 3, 11, 5, 2])))

main()

from heapq import *

def find_k_frequent_numbers(nums, k):

  # find the frequency of each number
  numFrequencyMap = {}
  for num in nums:
    numFrequencyMap[num] = numFrequencyMap.get(num, 0) + 1

  minHeap = []

  # go through all numbers of the numFrequencyMap and push them in the minHeap, which will have
  # top k frequent numbers. If the heap size is more than k, we remove the smallest(top) number
  for num, frequency in numFrequencyMap.items():
    heappush(minHeap, (frequency, num))
    if len(minHeap) > k:
      heappop(minHeap)

  # create a list of top k numbers
  topNumbers = []
  while minHeap:
    topNumbers.append(heappop(minHeap)[1])

  return topNumbers

def main():

  print("Here are the K frequent numbers: " +
        str(find_k_frequent_numbers([1, 3, 5, 12, 11, 12, 11], 2)))

  print("Here are the K frequent numbers: " +
        str(find_k_frequent_numbers([5, 12, 11, 3, 11], 2)))

main()

from heapq import *

def sort_character_by_frequency(str):

  # find the frequency of each character
  charFrequencyMap = {}
  for char in str:
    charFrequencyMap[char] = charFrequencyMap.get(char, 0) + 1

  maxHeap = []
  # add all characters to the max heap
  for char, frequency in charFrequencyMap.items():
    heappush(maxHeap, (-frequency, char))

  # build a string, appending the most occurring characters first
  sortedString = []
  while maxHeap:
    frequency, char = heappop(maxHeap)
    for _ in range(-frequency):
      sortedString.append(char)

  return ''.join(sortedString)

def main():

  print("String after sorting characters by frequency: " +
        sort_character_by_frequency("Programming"))
  print("String after sorting characters by frequency: " +
        sort_character_by_frequency("abcbab"))

main()

from heapq import *

class KthLargestNumberInStream:
  minHeap = []

  def __init__(self, nums, k):
    self.k = k
    # add the numbers in the min heap
    for num in nums:
      self.add(num)

  def add(self, num):
    # add the new number in the min heap
    heappush(self.minHeap, num)

    # if heap has more than 'k' numbers, remove one number
    if len(self.minHeap) > self.k:
      heappop(self.minHeap)

    # return the 'Kth largest number
    return self.minHeap[0]

def main():

  kthLargestNumber = KthLargestNumberInStream([3, 1, 5, 12, 2, 11], 4)
  print("4th largest number is: " + str(kthLargestNumber.add(6)))
  print("4th largest number is: " + str(kthLargestNumber.add(13)))
  print("4th largest number is: " + str(kthLargestNumber.add(4)))

main()

from heapq import *

def find_closest_elements(arr, K, X):
  index = binary_search(arr, X)
  low, high = index - K, index + K

  low = max(low, 0)  # 'low' should not be less than zero
  # 'high' should not be greater the size of the array
  high = min(high, len(arr) - 1)

  minHeap = []
  # add all candidate elements to the min heap, sorted by their absolute difference from 'X'
  for i in range(low, high+1):
    heappush(minHeap, (abs(arr[i] - X), arr[i]))

  # we need the top 'K' elements having smallest difference from 'X'
  result = []
  for _ in range(K):
    result.append(heappop(minHeap)[1])

  result.sort()
  return result

def binary_search(arr,  target):
  low, high = 0, len(arr) - 1
  while low <= high:
    mid = int(low + (high - low) / 2)
    if arr[mid] == target:
      return mid
    if arr[mid] < target:
      low = mid + 1
    else:
      high = mid - 1
  if low > 0:
    return low - 1
  return low

def main():
  print("'K' closest numbers to 'X' are: " +
        str(find_closest_elements([5, 6, 7, 8, 9], 3, 7)))
  print("'K' closest numbers to 'X' are: " +
        str(find_closest_elements([2, 4, 5, 6, 9], 3, 6)))
  print("'K' closest numbers to 'X' are: " +
        str(find_closest_elements([2, 4, 5, 6, 9], 3, 10)))

main()

from heapq import *

def find_maximum_distinct_elements(nums, k):
  distinctElementsCount = 0
  if len(nums) <= k:
    return distinctElementsCount

  # find the frequency of each number
  numFrequencyMap = {}
  for i in nums:
    numFrequencyMap[i] = numFrequencyMap.get(i, 0) + 1

  minHeap = []
  # insert all numbers with frequency greater than '1' into the min-heap
  for num, frequency in numFrequencyMap.items():
    if frequency == 1:
      distinctElementsCount += 1
    else:
      heappush(minHeap, (frequency, num))

  # following a greedy approach, try removing the least frequent numbers first from the min-heap
  while k > 0 and minHeap:
    frequency, num = heappop(minHeap)
    # to make an element distinct, we need to remove all of its occurrences except one
    k -= frequency - 1
    if k >= 0:
      distinctElementsCount += 1

  # if k > 0, this means we have to remove some distinct numbers
  if k > 0:
    distinctElementsCount -= k

  return distinctElementsCount

def main():

  print("Maximum distinct numbers after removing K numbers: " +
        str(find_maximum_distinct_elements([7, 3, 5, 8, 5, 3, 3], 2)))
  print("Maximum distinct numbers after removing K numbers: " +
        str(find_maximum_distinct_elements([3, 5, 12, 11, 12], 3)))
  print("Maximum distinct numbers after removing K numbers: " +
        str(find_maximum_distinct_elements([1, 2, 3, 3, 3, 3, 4, 4, 5, 5, 5], 2)))

main()

from heapq import *

def find_sum_of_elements(nums, k1, k2):
  minHeap = []
  # insert all numbers to the min heap
  for num in nums:
    heappush(minHeap, num)

  # remove k1 small numbers from the min heap
  for _ in range(k1):
    heappop(minHeap)

  elementSum = 0
  # sum next k2-k1-1 numbers
  for _ in range(k2 - k1 - 1):
    elementSum += heappop(minHeap)

  return elementSum

def main():

  print("Sum of all numbers between k1 and k2 smallest numbers: " +
        str(find_sum_of_elements([1, 3, 12, 5, 15, 11], 3, 6)))
  print("Sum of all numbers between k1 and k2 smallest numbers: " +
        str(find_sum_of_elements([3, 5, 8, 7], 1, 4)))

main()

from heapq import *

def rearrange_string(str):
  charFrequencyMap = {}
  for char in str:
    charFrequencyMap[char] = charFrequencyMap.get(char, 0) + 1

  maxHeap = []
  # add all characters to the max heap
  for char, frequency in charFrequencyMap.items():
    heappush(maxHeap, (-frequency, char))

  previousChar, previousFrequency = None, 0
  resultString = []
  while maxHeap:
    frequency, char = heappop(maxHeap)
    # add the previous entry back in the heap if its frequency is greater than zero
    if previousChar and -previousFrequency > 0:
      heappush(maxHeap, (previousFrequency, previousChar))
    # append the current character to the result string and decrement its count
    resultString.append(char)
    previousChar = char
    previousFrequency = frequency+1  # decrement the frequency

  # if we were successful in appending all the characters to the result string, return it
  return ''.join(resultString) if len(resultString) == len(str) else ""

def main():
  print("Rearranged string:  " + rearrange_string("aappp"))
  print("Rearranged string:  " + rearrange_string("Programming"))
  print("Rearranged string:  " + rearrange_string("aapa"))

main()

from heapq import *
from collections import deque

def reorganize_string(str, k):
  if k <= 1:
    return str

  charFrequencyMap = {}
  for char in str:
    charFrequencyMap[char] = charFrequencyMap.get(char, 0) + 1

  maxHeap = []
  # add all characters to the max heap
  for char, frequency in charFrequencyMap.items():
    heappush(maxHeap, (-frequency, char))

  queue = deque()
  resultString = []
  while maxHeap:
    frequency, char = heappop(maxHeap)
    # append the current character to the result string and decrement its count
    resultString.append(char)
    # decrement the frequency and append to the queue
    queue.append((char, frequency+1))
    if len(queue) == k:
      char, frequency = queue.popleft()
      if -frequency > 0:
        heappush(maxHeap, (frequency, char))

  # if we were successful in appending all the characters to the result string, return it
  return ''.join(resultString) if len(resultString) == len(str) else ""

def main():
  print("Reorganized string: " + reorganize_string("Programming", 3))
  print("Reorganized string: " + reorganize_string("mmpp", 2))
  print("Reorganized string: " + reorganize_string("aab", 2))
  print("Reorganized string: " + reorganize_string("aapa", 3))

main()

from heapq import *

def schedule_tasks(tasks, k):
  intervalCount = 0
  taskFrequencyMap = {}
  for char in tasks:
    taskFrequencyMap[char] = taskFrequencyMap.get(char, 0) + 1

  maxHeap = []
  # add all tasks to the max heap
  for char, frequency in taskFrequencyMap.items():
    heappush(maxHeap, (-frequency, char))

  while maxHeap:
    waitList = []
    n = k + 1  # try to execute as many as 'k+1' tasks from the max-heap
    while n > 0 and maxHeap:
      intervalCount += 1
      frequency, char = heappop(maxHeap)
      if -frequency > 1:
        # decrement the frequency and add to the waitList
        waitList.append((frequency+1, char))
      n -= 1

    # put all the waiting list back on the heap
    for frequency, char in waitList:
      heappush(maxHeap, (frequency, char))

    if maxHeap:
      intervalCount += n  # we'll be having 'n' idle intervals for the next iteration

  return intervalCount

def main():
  print("Minimum intervals needed to execute all tasks: " +
        str(schedule_tasks(['a', 'a', 'a', 'b', 'c', 'c'], 2)))
  print("Minimum intervals needed to execute all tasks: " +
        str(schedule_tasks(['a', 'b', 'a'], 3)))

main()

from heapq import *

class Element:

  def __init__(self, number, frequency, sequenceNumber):
    self.number = number
    self.frequency = frequency
    self.sequenceNumber = sequenceNumber

  def __lt__(self, other):
    # higher frequency wins
    if self.frequency != other.frequency:
      return self.frequency > other.frequency
    # if both elements have same frequency, return the element that was pushed later
    return self.sequenceNumber > other.sequenceNumber

class FrequencyStack:
  sequenceNumber = 0
  maxHeap = []
  frequencyMap = {}

  def push(self, num):
    self.frequencyMap[num] = self.frequencyMap.get(num, 0) + 1
    heappush(self.maxHeap, Element(
      num, self.frequencyMap[num], self.sequenceNumber))
    self.sequenceNumber += 1

  def pop(self):
    num = heappop(self.maxHeap).number
    # decrement the frequency or remove if this is the last number
    if self.frequencyMap[num] > 1:
      self.frequencyMap[num] -= 1
    else:
      del self.frequencyMap[num]

    return num

def main():
  frequencyStack = FrequencyStack()
  frequencyStack.push(1)
  frequencyStack.push(2)
  frequencyStack.push(3)
  frequencyStack.push(2)
  frequencyStack.push(1)
  frequencyStack.push(2)
  frequencyStack.push(5)
  print(frequencyStack.pop())
  print(frequencyStack.pop())
  print(frequencyStack.pop())

main()