import numpy as np
from sympy import cos, cosh, simplify, sinh, symbols

from einsteinpy.symbolic import GenericVector, MetricTensor

def euclidean_space_metric():
    symbolstr = "e1 e2"  # let angle between e1 & e2 be theta
    syms = symbols(symbolstr)
    th = symbols("theta")
    list2d = np.zeros((2, 2), dtype=int).tolist()
    # defining the metric tensor when axis are not orthogonal
    list2d[0][0] = list2d[1][1] = 1
    list2d[1][0] = list2d[0][1] = cos(th)
    metric = MetricTensor(list2d, syms, config="ll")
    return metric

def test_GenericVector_change_config_theoretical_test():
    # https://en.wikipedia.org/wiki/Covariance_and_contravariance_of_vectors#Definition
    a, b, th = symbols("a b theta")
    metric = euclidean_space_metric()
    # defining a contravariant vector
    cnvec = GenericVector([a, b], metric.syms, config="u", parent_metric=metric)
    covec = cnvec.change_config("l")  # get contravariant vector
    assert simplify(covec.tensor()[0] - (a + b * cos(th))) == 0
    assert simplify(covec.tensor()[1] - (b + a * cos(th))) == 0

def test_GenericVector_check_ValueErrors():
    a, b = symbols("a b")
    syms = symbols("e1 e2")
    # input a tensor with wring rank
    try:
        arr = [[a, b], [b, 1]]
        v1 = GenericVector(arr, syms, "l")
        boolstore = False
    except ValueError:
        boolstore = True
    assert boolstore
    # input a wrong length config
    try:
        arr = [a, b]
        v2 = GenericVector(arr, syms, "uu")
        boolstore = False
    except ValueError:
        boolstore = True
    assert boolstore

def test_lorentz_transform():
    def get_vector():
        syms = symbols("t x y z")
        t, x, y, z = syms
        return GenericVector([t, x, y, z], syms=syms, config="u")

    def get_lorentz_matrix():
        list2d = [[0 for t1 in range(4)] for t2 in range(4)]
        phi = symbols("phi")
        list2d[0][0], list2d[0][1], list2d[1][0], list2d[1][1] = (
            cosh(phi),
            -sinh(phi),
            -sinh(phi),
            cosh(phi),
        )
        list2d[2][2], list2d[3][3] = 1, 1
        return list2d

    t, x, phi = symbols("t x phi")
    v = get_vector().lorentz_transform(get_lorentz_matrix())
    print(v.tensor())
    assert simplify(v[0] - (t * cosh(phi) - x * sinh(phi))) == 0
    assert simplify(v[1] - (x * cosh(phi) - t * sinh(phi))) == 0


"""
  Name     : c11_12_normal_random.py
  Book     : Python for Finance (2nd ed.)
  Publisher: Packt Publishing Ltd.
  Author   : Yuxing Yan
  Date     : 6/6/2017
  email    : yany@canisius.edu
             paulyxy@hotmail.com
"""
import numpy as np
from scipy import stats,random
#
np.random.seed(12345)
n=5000000

ret = random.normal(0,1,n)
print('mean    =', np.mean(ret))
print('std     =',np.std(ret))
print('skewness=',stats.skew(ret))
print('kurtosis=',stats.kurtosis(ret))


# Project Euler Problem 6 Solution
#
# Problem statement:
# The sum of the squares of the first ten natural numbers is,
# 1^2 + 2^2 + ... + 10^2 = 385. The square of the sum of the
# first ten natural numbers is (1 + 2 + ... + 10)^2 = 55^2 = 3025.
# Hence the difference between the sum of the squares of the
# first ten natural numbers and the square of the sum is 3025 − 385 = 2640.
# Find the difference between the sum of the squares of the first
# one hundred natural numbers and the square of the sum.
#
# Solution description:
# Simple algebraic manipulations show, that the required sum equals
# 2*1*(2 + 3 + ... + n) + 2*2*(3 + 4 + 5 + ... + n) + 2*3*...
# This approach is implemented directly as a function with n as input.
# For some further utility, the function also takes another input m with
# default value m = 1, which determines the starting point for the summation.
#
# Author: Philipp Schuette
# Date: 2019/02/10
# License: MIT (see ../LICENSE.md)

import time

import numpy as np

def calc_sums(m, n):
	sum1 = 0  # gets incremented towards the final value
	sum2 = int((n*(n + 1) - m*(m + 1))/2)  # stores intermediate sums
	for i in range(m, n):
		sum1 += i*sum2
		sum2 -= (i + 1)
	return 2*sum1

if __name__ == "__main__":
    # calculate result and time it
    start = time.time()
    target = 100
    solution = calc_sums(1, target)
    end = time.time()

    # print result
    print("expired: {}s, solution: {}".format(
    np.round(end - start, 5), solution))


import numpy as np

def NewtonRaphson(f, fprime, x0, max_iter = 100, prec = 1e-10, verbose=False):

    x = [x0]
    x_val = x0

    for i in range(max_iter):

        val_i = f(x[i])
        df = fprime(x[i])
        epsilon = val_i/df
        x_val = x_val - epsilon
        x.append(x_val)

        if abs(epsilon) < prec:
            print(abs(df))
            return x_val, x
    if verbose:
        print(f"This calculation did not converge after {max_iter} iterations")

    return x_val, x

def NewtonRaphsonFact(f=None, fprime=None, x0=None, max_iter = 100, prec = 1e-10, verbose=False, **kwargs):

    x = [x0]
    x_val = x0

    for i in range(max_iter):

        val_i = f(x[i])
        df = fprime(x[i])
        epsilon = val_i/df
        x_val = x_val - epsilon
        x.append(x_val)

        if abs(epsilon) < prec:
            return i
    if verbose:
        print(f"This calculation did not converge after {max_iter} iterations")

    return i

def mandelbrot(c, max_iter = 80, **kwargs):
    z = 0
    n = 0
    while abs(z) <= 2 and n < max_iter:
        z = z**2 + c
        n += 1
    return n

def CreateImageMap(function, function_args, bounds, max_iter = 80, width = 200, height = 200):

    re_start, re_end, im_start, im_end = bounds
    if width > 1000:
        print(f'width of {width} is too large. Your computer only has so many pixels.')
        print("try zooming in with a smaller boundary to observe more detail")
        return

    if height > 1000:
        print(f'height of {height} is too large. Your computer only has so many pixels.')
        print("try zooming in with a smaller boundary to observe more detail")
        return

    X = np.zeros([width, height])
    for x in range(0, width):
        for y in range(0,height):
            real = re_start + (x/width) * ( re_end - re_start)
            imaginary = im_start + (y/width) * ( im_end - im_start)
            guess = complex(real, imaginary)
            try:
                function_args['mult']
            except KeyError:
                function_args['mult'] = 1.1

            function_args['x0'] = guess
            function_args['x1'] = function_args['mult'] * guess
            function_args['c'] = guess
            try:
                m = function(**function_args)
            except Exception as e:
                print(e)
                m = max_iter
            color = 255 - int(m * 255 / max_iter)

            X[x,y] = color

    return X

def secantfact(function, x0, x1, max_iter = 200, prec = 1e-5, verbose = False, **kwargs):

    f1 = function(x0)
    f = function(x1)

    if abs(f1) < abs(f):
        rts = x0
        x1 = x1
        f1, f = f, f1
    else:
        rts = x1
    for i in range(max_iter):
        dx = (x0 - rts) * f / (f - f1)
        x0 = rts
        f1 = f
        rts += dx
        f = function(rts)

        if abs(dx) < prec or f == 0:
            return i

    if verbose:
         print(f"This calculation did not converge after {max_iter} iterations")
    return i

def schroderfact(derivative, function, secondder, x0, prec = 1e-5, max_iter = 50, **kwargs):
    check = 1
    xim1 = x0
    n = 0
    while prec < check:
        num = (function(xim1) * derivative(xim1))
        dem = derivative(xim1)**2 - function(xim1) * secondder(xim1)
        xi = xim1 - num / dem
        n += 1
        check = abs(xi - xim1)
        xim1 = xi
        # print(check)
        if n == max_iter:
            break
    return  n

def halleyfact(derivative, function,seconder, x0, prec = 1e-5, max_iter = 100, **kwargs):
    check = 1
    xim1 = x0
    n = 0
    for i in range(max_iter):

        a = function(xim1) * seconder(xim1)
        b = 2 * derivative(xim1) ** 2
        c = 1 - a/b

        d = derivative(xim1) * c
        xi = xim1 - function(xim1) / d
        n += 1
        check = abs(xi - xim1)
        xim1 = xi
        eps = abs(function(xim1) / d)

        if eps < prec:
            break

    return  n

def nderiv(func, x, eps=np.sqrt(np.finfo(float).eps)):
    ''' Takes a vector of each component of a multivariate
    function and returns its Jacobian matrix as computed by
    finite differences'''

    N = len(x)

    J = [[None for i in range(N)] for j in range(N)]
    #xh is x + h in the derivative formula
    xh = x
    # very bad quick fix, will not work as a gradient
    if isinstance(x[0], complex):
        eps = complex(eps, eps)
    for i in range(N):
        temp = xh[i]
        h = eps * temp
        if h == 0: h = eps
        xh[i] = temp + h # scootch that point over
        # evalueat f(x+h)
        f = func(xh)

        xh[i] = temp
        fvec = func(x)
        # forward difference formula
        for j in range(N):
            J[j][i] = (f[j] - fvec[j])/h

    if len(x) == 1:
        return J[0][0]

    return J


import numpy as np

def gaussian(x,x0=0,sigma=1):
    '''Numpy implementation of gaussian'''
    return np.exp(
        -np.power((x - x0) / sigma, 2) / 2
    ) / (np.sqrt(2 * np.pi) * sigma)

def cumulative_gaussian_lut(step:float=0.01, sigma_count:int=3):
    '''
    Cumulative and normalized gaussian Lookup table.

    1. Function creates gaussian with x0 = 0.5 and sigma = 0.5 / 3 in range
       from 0 to 1.
       According to 3 sigma rule 99.7% values are in range from 0 to 1.
    2. Calculates cumulative sum on gaussian
    4. Normalize by max value

    Arguments are in range [0;1) and values are in range [0;1].
    Argument 0 has value 0.

    Parameters
    ==========
    step: float, optional
        Resolution of LUT. The smaller value, the less accuracy you get.
        The bigger value, the more memory you use. 0.01-0.001 should be good.
    sigma_count: int, optional
        What multiple of sigma should the half of width be.
        According the 1 sigma rule in range +- 1 sigma is 68.2% values.
        According the 2 sigma rule in range +- 2 sigma is 95.4% values.
        According the 3 sigma rule in range +- 3 sigma is 99.7% values.
        According the 4 sigma rule in range +- 4 sigma is 99.994% values.
        You may to use this parameter to control value change rate.
        1 sigma - linear, 4 sigma - slow at begin and at end, fast in middle.

    Returns
    =======
    Function for access to approximated value for given argument.
    It accepts argument from range [0;1) (from 0 (inclusive) to 1 (exclusive)).
    Returns 0 ir 1 if index out of bounds.
    Return the nearest precalculated for given argument (range (0; 1]
    from 0 (exclusive) to 1 (exclusive))).

    Examples
    ========
    >>> lut = cumulative_reversed_gaussian_lut()
    >>> lut(0)
        0
    >>> lut(0.5)
        0.49881326466597947
    >>> lut(0.25)
        0.9339886741945999
    '''
    a = np.arange(0, 1, step)
    width = 1
    half_width = width / 2
    x0 = half_width
    sigma = half_width / sigma_count

    gx = gaussian(a, x0=x0, sigma=sigma)
    cs = np.cumsum(gx)
    max_ = cs[len(cs) - 1]
    normalized_cs = cs / max_

    def get_value(x):
        if x < 0:
            return 0
        elif x >= 1:
            return 1
        idx = int(x / step)
        return normalized_cs[idx]
    return get_value

if __name__ == '__main__':
    # Example usage. Draw gaussian plots and cumulative, normalized
    # plots for different sigma.

    step = 0.001
    lut_count = 4
    r = range(1, lut_count + 1)
    luts = [cumulative_gaussian_lut(step=step, sigma_count=i)
                for i in r]
    a = [i * step for i in range(0, int(1 / step))]

    from matplotlib import pyplot as plt
    plt.subplot(1, 2, 1)
    for lut in luts:
        plt.plot(a, [lut(i) for i in a])
    plt.legend(["%d sigma" % (i,) for i in r])

    plt.subplot(1, 2, 2)
    for i in range(1, lut_count + 1):
        sigma = 1 / i
        g = gaussian(np.array(a), 0.5, sigma)
        max_ = g.max()
        g = g / max_
        plt.plot(a, g)
    plt.legend(["%d sigma" % (i,) for i in r])
    plt.suptitle(('Cumulative, normalized gaussian'))
    plt.show()


import numpy as np

def decimal_to_binlist(decimal, digits): # ex) 6,3 --> [1,1,0]

    bin_str = "{:0{digits}b}".format(decimal, digits=digits)
    return  [int(s) for s in list(bin_str)]

def binlist_to_decimal(bin_list): # ex) [0,1,1] --> 3

    return int("".join([str(i) for i in bin_list]), 2)

def make_hamming_matrix(r):

    # parity check matrix (H)
    A = []
    for x in range(1,2**r):
        bin_list = decimal_to_binlist(x, r)
        if sum(bin_list) == 1: continue
        A.append(bin_list)
    A = np.array(A)
    I_H = np.eye(r, dtype=int)
    H = np.concatenate([A, I_H])

    # represent integer each row of H matrix (for error correction algorithm)
    H_int = [binlist_to_decimal(row) for row in H]

    # generator matrix (G)
    I_G = np.eye(2**r-r-1, dtype=int)
    G = np.concatenate([I_G, A], 1)

    return G, H, H_int

def generate_data(k, N):  # random k-bits data

    for _ in range(N):
        yield np.random.randint(2, size=k)

def add_noise(d_in):  # bit flip to one bit (select randomly)

    idx = np.random.randint(len(d_in))
    err = np.array([1 if i == idx else 0 for i in range(len(d_in))])
    d_out = (d_in + err) % 2
    return d_out

def correct_error(d_in, H_int):

    d_out = d_in.copy()
    p = (d_out @ H) % 2
    x = binlist_to_decimal(p)
    err_idx = H_int.index(x)
    d_out[err_idx] = (d_out[err_idx] + 1) % 2  # bit flip (recover)
    return d_out

if __name__ == '__main__':

    r = 3
    n = 2**r - 1
    k = 2**r - r - 1
    N = 10

    G, H, H_int  = make_hamming_matrix(r)

    print("* input(random) -> encode -> add noise(random 1-bit flip) -> correct -> decode:")
    err_count = 0
    for x in generate_data(k, N):
        y = (x @ G)%2
        y_error = add_noise(y)
        y_correct = correct_error(y_error, H_int)
        x_correct = y_correct[0:k]  # decode (= extract 1st to k-th elements)
        print("{0:} -> {1:} -> {2:} -> {3:} -> {4:}".format(x,y,y_error,y_correct,x_correct))

        if sum((x+x_correct)%2) == 1: # if x != x_correct --> 1
            err_count += 1

    err_rate = err_count / N
    print("* error rate = {0:} (count:{1:} / total:{2:})".format(err_rate, err_count, N))


import numpy as np

def _fourDVR(start,stop,num):
    """
    Calculate periodic Fourier (exponential) DVR grid and operators.

    Parameters
    ----------
    start : float
        Grid start value
    stop : float
        Grid stop value. Must be larger than start
    num : int
        Number of grid points. Must be >= 3 and odd.

    Returns
    -------
    grid : ndarray
        Array of DVR grid points
    D : ndarray
        First derivative operator in DVR basis, shape (num, num)
    D2 : ndarray (num,num)
        Second derivative operator in DVR basis, shape (num, num)

    """

    if stop <= start:
        raise ValueError("stop value must be larger than start value")
    if num < 3 :
        raise ValueError("num must be >= 3")
    if num % 2 == 0:
        raise ValueError("num must be odd")

    grid = np.linspace(start, stop, num+1)[0:num]
    period = stop - start

    D = np.ndarray((num,num))
    D2 = np.ndarray((num,num))

    for i in range(num):
        for j in range(i,num):
            delta = i - j
            if delta == 0:
                D[i,j] = 0
                D2[i,j] = -(np.pi / period)**2 * (1/3.0) * (num**2 - 1)
            else:
                D[i,j] = (np.pi / period) * (-1)**delta / np.sin(np.pi*delta/num)
                D[j,i] = -D[i,j]

                D2[i,j] = -2*(np.pi / period)**2 * (-1)**delta * np.cos(np.pi * delta / num) / (np.sin(np.pi*delta/num)**2)
                D2[j,i] = +D2[i,j]

    return grid, D, D2

def _fourDVRwfs(q, start, stop, num):
    """
    Calculate Fourier (exponential) DVR wavefunctions.

    Parameters
    ----------
    q : ndarray
        A 1D array of coordinate values.
    start : float
        DVR grid start value.
    stop : float
        DVR grid stop value.
    num : int
        The number of DVR grid points

    Returns
    -------
    wfs : ndarray
        A (`q`.size, `num`) shaped array with
        the DVR wavefunctions evaluated at grid points `q`.

    """

    if np.ndim(q) != 1:
        raise ValueError("q must be 1-dimensional")
    if stop <= start:
        raise ValueError("stop value must be larger than start value")
    if num < 3 :
        raise ValueError("num must be >= 3")
    if num % 2 == 0:
        raise ValueError("num must be odd")

    nq = q.size

    period = stop - start

    wfs = np.ndarray((nq,num), dtype = q.dtype)

    m = (num-1)//2 # max frequency

    for i in range(num): # DVR function at i^th grid point
        t = 1
        for k in range(1,m+1): # Calculate exponential sum as cosines explicitly
            t += 2*np.cos(k*(q - start - i*period/num) * 2*np.pi/period)

        wfs[:,i] = t/np.sqrt(num*period)

    return wfs


import matplotlib.pyplot as plt
import numpy as np
from numpy.polynomial.polynomial import Polynomial
from scipy.interpolate import lagrange

# Interpolate basis vector e1.
plt.figure()
x = np.linspace(0, 1, 5)
e1 = np.array([1, 0, 0, 0, 0])
x_fine = np.linspace(0, 1)
print(f"x = {x}")

poly = lagrange(x, e1)
coef1 = poly.coef[::-1] # reverse order of coefficients

plt.scatter(x, e1, color="red", label="points and values")
plt.plot(x_fine, Polynomial(coef1)(x_fine), label="Lagrange polynomial")
plt.legend()
plt.show()

# Interpolate five basis vectors e1, e2, e3, e4, e5.
e2 = np.array([0, 1, 0, 0, 0])
e3 = np.array([0, 0, 1, 0, 0])
e4 = np.array([0, 0, 0, 1, 0])
e5 = np.array([0, 0, 0, 0, 1])

coef2 = lagrange(x, e2).coef[::-1] # reverse order of coefficients
coef3 = lagrange(x, e3).coef[::-1] # reverse order of coefficients
coef4 = lagrange(x, e4).coef[::-1] # reverse order of coefficients
coef5 = lagrange(x, e5).coef[::-1] # reverse order of coefficients

plt.figure()
plt.plot(x_fine, Polynomial(coef1)(x_fine), label="Lagrange polynomial of e1")
plt.plot(x_fine, Polynomial(coef2)(x_fine), label="Lagrange polynomial of e2")
plt.plot(x_fine, Polynomial(coef3)(x_fine), label="Lagrange polynomial of e3")
plt.plot(x_fine, Polynomial(coef4)(x_fine), label="Lagrange polynomial of e4")
plt.plot(x_fine, Polynomial(coef5)(x_fine), label="Lagrange polynomial of e5")
plt.legend()
plt.show()

# Interpolate arbitrary data vector y
y = np.random.sample(5)*10-5
coef = lagrange(x, y).coef[::-1] # reverse order of coefficients

plt.figure()
plt.scatter(x, y, color="red", label="points and values")
plt.plot(x_fine, Polynomial(coef1)(x_fine)*y[0] + Polynomial(coef2)(x_fine)*y[1] + Polynomial(coef3)(x_fine)*y[2] + Polynomial(coef4)(x_fine)*y[3] + Polynomial(coef5)(x_fine)*y[4], label="Sum")
plt.plot(x_fine, Polynomial(coef)(x_fine), label="Lagrange polynomial", linestyle="--")
plt.legend()
plt.show()


"""

"""
import numpy as np
import pandas as pd
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def costfunction(X,y,theta):
    m = np.size(y)

    #Cost function in vectorized form
    h = X @ theta
    J = float((1./(2*m)) * (h - y).T @ (h - y));
    return J

def gradient_descent(X,y,theta,alpha = 0.0005,num_iters=1000):
    #Initialisation of useful values
    m = np.size(y)
    J_history = np.zeros(num_iters)
    theta_0_hist, theta_1_hist = [], [] #For plotting afterwards

    for i in range(num_iters):
        #Grad function in vectorized form
        h = X @ theta

        # update parameters by gradient descent
        theta = theta - alpha * (1/m)* (X.T @ (h-y))

        #Cost and intermediate values for each iteration
        J_history[i] = costfunction(X,y,theta)
        theta_0_hist.append(theta[0,0])
        theta_1_hist.append(theta[1,0])

    return theta,J_history, theta_0_hist, theta_1_hist

#Creating the dataset (as previously)
x = np.linspace(0,1,40)
noise = 1*np.random.uniform(  size = 40)
y = np.sin(x * 1.5 * np.pi )
y_noise = (y + noise).reshape(-1,1)
X = np.vstack((np.ones(len(x)),x)).T

#Setup of meshgrid of theta values
T0, T1 = np.meshgrid(np.linspace(-1,3,100),np.linspace(-6,2,100))

#Computing the cost function for each theta combination
zs = np.array(  [costfunction(X, y_noise.reshape(-1,1),np.array([t0,t1]).reshape(-1,1))
                     for t0, t1 in zip(np.ravel(T0), np.ravel(T1)) ] )
#Reshaping the cost values
Z = zs.reshape(T0.shape)

#Computing the gradient descent
theta_result,J_history, theta_0, theta_1 = gradient_descent(X,y_noise,np.array([0,-6]).reshape(-1,1),alpha = 0.3,num_iters=1000)

#Angles needed for quiver plot
anglesx = np.array(theta_0)[1:] - np.array(theta_0)[:-1]
anglesy = np.array(theta_1)[1:] - np.array(theta_1)[:-1]

fig = plt.figure(figsize = (16,8))

#Surface plot
ax = fig.add_subplot(1, 2, 1, projection='3d')
ax.plot_surface(T0, T1, Z, rstride = 5, cstride = 5, cmap = 'jet', alpha=0.5)
ax.plot(theta_0,theta_1,J_history, marker = '*', color = 'r', alpha = .4, label = 'Gradient descent')

ax.set_xlabel('theta 0')
ax.set_ylabel('theta 1')
ax.set_zlabel('Cost function')
ax.set_title('Gradient descent: Root at {}'.format(theta_result.ravel()))
ax.view_init(45, 45)

#Contour plot
ax = fig.add_subplot(1, 2, 2)
ax.contour(T0, T1, Z, 70, cmap = 'jet')
ax.quiver(theta_0[:-1], theta_1[:-1], anglesx, anglesy, scale_units = 'xy', angles = 'xy', scale = 1, color = 'r', alpha = .9)
# plt.axis('equal')
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ch9Python.py. Nonlinear regression.

import matplotlib.pyplot as plt
import numpy as np
import statsmodels.api as sm

x1 = [1.00,1.25,1.50,1.75,2.00,2.25,2.50,2.75,3.00,3.25,3.50,3.75,4.00]
y = [3.34,4.97,4.15,5.40,5.21,4.56,3.69,5.86,4.58,6.94,5.57,5.62,6.87]

# Convert data to vectors.
x1 = np.array(x1)
y = np.array(y)
n = len(y)
x2 = x1**2 # define x2 as square of x1.

###############################
# Quadratic model. Repeated twice: 1) Vector-matrix, 2) Standard library.
###############################
ymean = np.mean(y)
ones = np.ones(len(y)) # 1 x n vector
Xtr = [ones, x1, x2]   # 3 x n matrix
X = np.transpose(Xtr)  # n x 3 matrix
y = np.transpose(y)    # 1 x n vector

# 1) Find slopes and intercept using vector-matrix notation.
Xdot = np.dot(Xtr,X)
Xdotinv = np.linalg.pinv(Xdot)
XdotinvA = np.dot(Xdotinv,Xtr)
params = np.dot(XdotinvA,y)

b0Quadratic = params[0] # 3.819
b1Quadratic = params[1] # 0.212
b2Quadratic = params[2] # 0.111

print('\nQUADRATIC VECTOR-MATRIX PARAMETERS')
print('slope b1 = %6.3f' % b1Quadratic)
print('slope b2 = %6.3f' % b2Quadratic)
print('intercept b0 = %6.3f' % b0Quadratic)

# 2) STANDARD LIBRARY Quadratic output.
quadraticModel = sm.OLS(y, X).fit()
print('\n\nQUADRATIC MODEL SUMMARY')
print(quadraticModel.params)
print(quadraticModel.summary())

###############################
# Linear model (using standard library).
###############################
Xtr = [ones, x1]
X = np.transpose(Xtr)
linearModel = sm.OLS(y, X).fit()
print('\n\nLINEAR MODEL SUMMARY')
print(linearModel.params)
print(linearModel.summary())

params = linearModel.params
b0LINEAR = params[0] # 3.225
b1LINEAR = params[1] # 0.764
yhatLINEAR = b1LINEAR * x1 + b0LINEAR

###############################
# PLOT DATA.
###############################
fig = plt.figure(1)
fig.clear()
yhatQuadratic = b1Quadratic * x1 + b2Quadratic * x2 + b0Quadratic

plt.plot(x1, y, "o", label="Data")
plt.plot(x1, yhatQuadratic, "b--",label="Quadratic fit")
plt.plot(x1, yhatLINEAR, "r--",label="Linear fit")
plt.legend(loc="best")
plt.show()

###############################
# STANDARD LIBRARY: Results of extra sum of squares method.
###############################
# test hypothesis that x2=0
hypothesis = '(x2 = 0)'
f_test = quadraticModel.f_test(hypothesis)
print('\nResults of extra sum of squares method:')
print('F df_num = %.3f df_denom = %.3f'
% (f_test.df_num, f_test.df_denom))       # 1, 10
print('F partial = %.3f' % f_test.fvalue) # 1.127
print('p-value (that x2=0) = %.3f' % f_test.pvalue)   # 0.729

###############################
# END OF FILE.
###############################


import math
import numpy as np
from matplotlib import pyplot as plt
from scipy import optimize
from methods import *
from pprint import pprint

def FirstDerivateSchwefelsFunction(x):
    result = []

    x_list = x.getA()[0]

    for i in x_list:
        result.append(-(math.sin(math.sqrt(abs(i))) + (i**2*math.cos(math.sqrt(abs(i)))) / (2 * math.sqrt(abs(i)**3))))

    return np.matrix([[x] for x in result])

def SecondDerivateSchwefelsFunction(x):
    x_list = x.getA()[0]

    result = [[0 for i in range(len(x_list))] for j in range(len(x_list))]

    for ind, i in enumerate(x_list):
        result[ind][ind] = ((i*math.pow(abs(i), 7/2)*math.sin(math.sqrt(abs(i)))-3*i**3*abs(i)*math.cos(math.sqrt(abs(i)))) / (4*math.pow(abs(i), 9/2)))

    return np.matrix(result)

#-------F(x)--------------
def F(x):
    result = 0

    for i in x:
        result += i * math.sin(math.sqrt(abs(i)))

    return -result

#--------For x_i <= 500 restrictions-------------
def g_i_1(x_i : float):
    return x_i -500

def g_i_1_plus(x_i : float):
    return max(0,x_i -500)
#------For x_i>= -500 restrictions---------------
def g_i_2(x_i : float):
    return -x_i-500

def g_i_2_plus(x_i : float):
    return max(0,-x_i-500)

#------Q(x,c)-for penalization method----------------

def Q(c):
    def Q_call(x):
        f_x_eval = F(x)

        g_i_1_sum = 0
        for variable in x:
            g_i_1_sum +=g_i_1_plus(variable)

        g_i_2_sum = 0
        for variable in x:
            g_i_2_sum +=g_i_2_plus(variable)

        return f_x_eval + c * g_i_1_sum + c * g_i_2_sum

    return Q_call

#------R(x,miu)- for barrier method-------------------
def R(miu):
    def R_call(x):
        f_x_eval = F(x)

        g_i_1_sum = 0
        for variable in x:
            g_i_1_sum -=1/g_i_1(variable)

        g_i_2_sum = 0
        for variable in x:
            g_i_2_sum -=1/g_i_2(variable)

        return f_x_eval + miu * g_i_1_sum + miu * g_i_2_sum

    return R_call

#------Omega( chequear si un vector x cumple con las restricciones)-------
def omega(x):
    # print(x)
    for element in x:
        # print(element)
        if element<-500 or element>500:
            return False
    return True

def plot():
    x = np.arange(-500, 500, 0.1)
    y = [F([i]) for i in x]

    plt.plot(x, y)
    plt.show()

#testing-------------------
if __name__ == '__main__':
    # plot()

    # ans = Penalization_method("BFGS", Q, omega, x0=np.array([770,770]), c0=1, alpha=1.5, epsilon=0.001, k_max=500)
    ans = Barrier_method("BFGS", R, x0=np.array([430,430]), miu_0=1, alpha=0.5, epsilon=0.001, k_max=500)
    # print("Penalization Method")
    # pprint(ans)
    # print()
    # print("Barrier Method")
    print(F(ans["1.Result"]))
    pprint(ans)
    # print()
    # print("SQP Method")
    # print(SQP_method(F, x0=np.array([380,380]), bounds=[(-500, 500), (-500, 500)], k_max=500))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri May 31 11:04:56 2019

@author: fietekrutein

A script to find a new direction of an equality constrained
convex optimization problem using pure Newton's method
"""

import numpy as np

# functions as of example problem

def exp1(x):
    return(np.exp(x[0] + 3*x[1] + x[2] - 0.1))

def exp2(x):
    return (np.exp(x[0] - 3*x[1] + 2*x[2] - 0.1))

def exp3(x):
    return (np.exp(-x[0] - x[1] - 2*x[2] - 0.1))

def obj(x):
    return (exp1(x) + exp2(x) + exp3(x))

def grad(x):
    i1 = exp1(x) + exp2(x) - exp3(x)
    i2 = 3*exp1(x) - 3*exp2(x) - exp3(x)
    i3 = exp1(x) + 2*exp2(x) - 2*exp3(x)
    return (np.array([i1,i2,i3]))

def hess(x):
    i11 = exp1(x) + exp2(x) + exp3(x)
    i12 = 3*exp1(x) -3*exp2(x) + exp3(x)
    i13 = exp1(x) + 2*exp2(x) + 2*exp3(x)

    i21 = 3*exp1(x) - 3*exp2(x) + exp3(x)
    i22 = 9*exp1(x) + 9*exp2(x) + exp3(x)
    i23 = 3*exp1(x) - 6*exp2(x) + 2*exp3(x)

    i31 = exp1(x) + 2*exp2(x) + 2*exp3(x)
    i32 = 3*exp1(x) - 6*exp2(x) + 2*exp3(x)
    i33 = exp1(x) + 4*exp2(x) + 4*exp3(x)

    return (np.array([[i11,i12,i13],
                      [i21,i22,i23],
                      [i31,i32,i33]]))

# new direction search formulation

def NewDir(x, A):
    g = grad(x)
    h = hess(x)
    h_inv = np.linalg.inv(h)
    d = -np.dot(h_inv, g) + np.dot(np.dot(np.dot(h_inv, A.T),
                  np.linalg.inv(np.dot(A, np.dot(h_inv, A.T)))), np.dot(A, np.dot(h_inv, g)))
    return (d)

# initialize example
A = np.array([[1,2,0],
              [4,0,5]])
x = np.array([1,1,2/5])

# execute algorithm
NewDir(x,A)

# check null space / whether decent direction
xnew = x + NewDir(x,A)
d2 = NewDir(x,A)
nspace_t = np.dot(A,d2)
np.dot(grad(x).T, d2)


#Find Bell Numbers

def BellNumber(index):
    bell=[[0 for i in range(index+1)] for j in range(index+1)]
    bell[0][0] = 1
    for i in range(1,index+1):
        bell[i][0]=bell[i-1][i-1]
        for j in range(1,i+1):
            bell[i][j]=bell[i-1][j-1]+bell[i][j-1]
    return bell[index][0]

def MPmath(index,dps=30):
    import mpmath
    mpmath.mp.dps = dps
    return int(mpmath.bell(index))

def DobinskiFormula(n):
    from math import e
    from math import factorial
    try:
        return round((1/e) * sum([(k**(n))/(factorial(k)) for k in range(1,1000)]))
    except:
        return "inf"

def doTest(toPrint=False,toProgress=False,start=0,toEnd=1000,algo="s"):
    s=set()
    KK=10000
    from IPython.display import clear_output
    for i in range(start,toEnd+1):
        if(toProgress and (i<KK or (i>=KK and i%(KK/100)==0))):
            clear_output(wait=True)
            print(i,end="\t")
        if(algo=="s"):
            bell=BellNumber(i)
        elif(algo=="mpmath"):
            bell=MPmath(i)
        elif(algo=="dobinski"):
            bell=DobinskiFormula(i)
        if(bell):
            s.add(bell)
            if(toPrint and not toProgress):
                print(bell,end=", ")
        if(toProgress and (i<KK or (i>=KK and i%(KK/100)==0))):
            print(s)
    if(not toPrint):
        return s

#BellNumber(2000)
#MPmath(2000)
#DobinskiFormula(4)
#doTest(False,False,1,500) #7.97s
#doTest(False,False,1,500,"dobinski") #2.95s
#doTest(False,False,1,500,"mpmath") #1.73s


import numpy as np

class LogisticRegression:

    # Initialize with features and labels
    def __init__(self, X, Y):
        self.X = X
        self.Y = Y
        self.w = np.ones(X.shape[1])
        self.N = X.shape[0]

    # average cost function
    # w is the weights
    # X is the design matrix
    # y is the labels
    def cost(self):
        z = np.dot(self.X, self.w)
        J = np.mean(self.Y * np.log1p(np.exp(-z)) + (1 - self.Y) * np.log1p(np.exp(z)))
        return J

    # logistic function on x
    def logistic(self, x):
        return 1 / (1 + np.exp(-x))

    # gradient of logistic regression
    def gradient(self, regularization):

        # Calculate y_hat based on logistic func
        y_hat = self.logistic(np.dot(self.X, self.w))

        # Gradient of logistic descent
        gradient = np.dot(self.X.T, y_hat - self.Y) / self.N

        # L2 regularization
        gradient[1:] += regularization * self.w[1:]

        return gradient

    # lr is the learning rate
    # epochs is the number of iterations
    # w is the weights to be learned, default value is 0 array
    # eps is the termination condition, when the norm of the gradient is less than the value
    def fit(self, lr=0.5, epochs=10000, regularization=0, verbose=False, eps=1e-2):

        # Iterate epochs times, performing gradient descent
        for epoch in range(epochs):
            gradient = self.gradient(regularization)

            # go down the gradient with given learning rate
            self.w -= lr * gradient

            # print details about the training if needed
            if verbose:
                # every 1000 epochs, print the cost
                if epoch % 1000 == 0:
                    print('iter: ', epoch, ' cost: ', self.cost())

            if eps != None and np.linalg.norm(gradient) < eps:
                #print('Reached min cost.')
                break

        return self.cost()

    # X is a feature instance, default decision boundary = 0.5
    def predict(self, X, boundary=0.5):

        return (self.logistic(np.dot(X, self.w)) > boundary).astype(int)


import math as ma
import numpy as np
from numba import jit

@jit(nopython=True)
def binomialTree (r, sigma, S0, T, K, M, call = True, European = True):
    """Price a vanilla option using the Cox, Ross and Rubinstein binomial tree method, based
    on the algorithm presented in the Computational Finance script at the University of Kiel.

    Keyword arguments:
    r -- risk free rate
    sigma -- annual volatility
    S0 -- initial stock price
    T -- maturity of the option
    K -- strike price of the option
    call -- boolean value to differentiate between call and put options (default: call)
    European -- boolean value to differentiate between European and American options (default: European)
    M -- number of periods
    """

    # step 1: calibrate the lattice and the risk neutral probability
    dt = T/M
    alpha = ma.exp(r*dt)
    beta = (ma.pow(alpha,-1)+alpha*ma.exp((sigma**2)*dt))/2
    u = beta + ma.sqrt(beta**2-1)
    d = ma.pow(u,-1)
    q = (ma.exp(r*dt)-d)/(u-d)

    # step 2: build two empty lattices & initialize the first entry of the stock prices
    stockPrice = np.empty((M,M))
    stockPrice[0,0] = S0

    optionPrice = np.empty((M,M))

    # step 3: fill the lattice up with all possible stock prize realizations
    for i in range(M+1):
        for j in range(i+1):
            stockPrice[j,i] = S0 * u**j * d**(i-j)

    # step 4: compute the option value for every row in the last column
    if call == True:
        for j in range(M+1):
            optionPrice[j,M] = max(0, stockPrice[j,M]-K)

    else:
        for j in range(M+1):
            optionPrice[j,M] = max(0, K-stockPrice[j,M])

    # step 5: compute the option value backwardly
    if European == True:
        for i in reversed(range(M)):
            optionPrice[j,i] = ma.exp(-r*dt)*(q*optionPrice[j+1,i+1]+(1-q)*optionPrice[j,i+1])

    else:
        if call == True:
            optionPrice[j,i] = max(max(0,stockPrice[j,i]-K), ma.exp(-r*dt)*(q*optionPrice[j+1,i+1]+(1-q)*optionPrice[j,i+1]))
        else:
            max(max(0,K-stockPrice[j,i]), ma.exp(-r*dt)*(q*optionPrice[j+1,i+1]+(1-q)*optionPrice[j,i+1]))

    # step 6: return the option value at time t=0
    return optionPrice[0,0]


# Plot polynomial regression on 1d problem
# Based on https://github.com/probml/pmtk3/blob/master/demos/linregPolyVsDegree.m

import numpy as np
import matplotlib.pyplot as plt
from pyprobml_utils import save_fig

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import MinMaxScaler
import sklearn.metrics
from sklearn.metrics import mean_squared_error as mse

def make_1dregression_data(n=21):
    np.random.seed(0)
    xtrain = np.linspace(0.0, 20, n)
    xtest = np.arange(0.0, 20, 0.1)
    sigma2 = 4
    w = np.array([-1.5, 1/9.])
    fun = lambda x: w[0]*x + w[1]*np.square(x)
    ytrain = fun(xtrain) + np.random.normal(0, 1, xtrain.shape) * \
        np.sqrt(sigma2)
    ytest= fun(xtest) + np.random.normal(0, 1, xtest.shape) * \
        np.sqrt(sigma2)
    return xtrain, ytrain, xtest, ytest

xtrain, ytrain, xtest, ytest = make_1dregression_data(n=21)

#Rescaling data
scaler = MinMaxScaler(feature_range=(-1, 1))
Xtrain = scaler.fit_transform(xtrain.reshape(-1, 1))
Xtest = scaler.transform(xtest.reshape(-1, 1))

degs = np.arange(1, 21, 1)
ndegs = np.max(degs)
mse_train = np.empty(ndegs)
mse_test = np.empty(ndegs)
ytest_pred_stored = np.empty(ndegs, dtype=np.ndarray)
ytrain_pred_stored = np.empty(ndegs, dtype=np.ndarray)
for deg in degs:
    model = LinearRegression()
    poly_features = PolynomialFeatures(degree=deg, include_bias=False)
    Xtrain_poly = poly_features.fit_transform(Xtrain)
    model.fit(Xtrain_poly, ytrain)
    ytrain_pred = model.predict(Xtrain_poly)
    ytrain_pred_stored[deg-1] = ytrain_pred
    Xtest_poly = poly_features.transform(Xtest)
    ytest_pred = model.predict(Xtest_poly)
    mse_train[deg-1] = mse(ytrain_pred, ytrain)
    mse_test[deg-1] = mse(ytest_pred, ytest)
    ytest_pred_stored[deg-1] = ytest_pred

# Plot MSE vs degree
fig, ax = plt.subplots()
mask = degs <= 15
ax.plot(degs[mask], mse_test[mask], color = 'r', marker = 'x',label='test')
ax.plot(degs[mask], mse_train[mask], color='b', marker = 's', label='train')
ax.legend(loc='upper right', shadow=True)
plt.xlabel('degree')
plt.ylabel('mse')
save_fig('polyfitVsDegree.pdf')
plt.show()

# Plot fitted functions
chosen_degs = [1, 2, 14, 20]
for deg in chosen_degs:
    fig, ax = plt.subplots()
    ax.scatter(xtrain, ytrain)
    ax.plot(xtest, ytest_pred_stored[deg-1])
    ax.set_ylim((-10, 15))
    plt.title('degree {}'.format(deg))
    save_fig('polyfitDegree{}.pdf'.format(deg))
    plt.show()

# Plot residuals
#https://blog.minitab.com/blog/adventures-in-statistics-2/why-you-need-to-check-your-residual-plots-for-regression-analysis
chosen_degs = [1, 2, 14, 20]
for deg in chosen_degs:
    fig, ax = plt.subplots()
    ypred =  ytrain_pred_stored[deg-1]
    residuals = ytrain - ypred
    ax.plot(ypred, residuals, 'o')
    ax.set_xlabel('predicted y')
    ax.set_ylabel('residual')
    plt.title('degree {}. Predictions on the training set'.format(deg))
    save_fig('polyfitDegree{}Residuals.pdf'.format(deg))
    plt.show()

# Plot fit vs actual
# https://blog.minitab.com/blog/adventures-in-statistics-2/regression-analysis-how-do-i-interpret-r-squared-and-assess-the-goodness-of-fit
chosen_degs = [1, 2, 14, 20]
for deg in chosen_degs:
    for train in [True, False]:
        if train:
            ytrue = ytrain
            ypred = ytrain_pred_stored[deg-1]
            dataset = 'Train'
        else:
            ytrue = ytest
            ypred = ytest_pred_stored[deg-1]
            dataset = 'Test'
        fig, ax = plt.subplots()
        ax.scatter(ytrue, ypred)
        ax.plot(ax.get_xlim(), ax.get_ylim(), ls="--", c=".3")
        ax.set_xlabel('true y')
        ax.set_ylabel('predicted y')
        r2 = sklearn.metrics.r2_score(ytrue, ypred)
        plt.title('degree {}. R2 on {} = {:0.3f}'.format(deg, dataset, r2))
        save_fig('polyfitDegree{}FitVsActual{}.pdf'.format(deg, dataset))
        plt.show()


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#calculate the Sum of Squared Error
def error(m, b, data):
    sum_of_squares = 0
    for i in range(len(data)):
        x = data[i, 0]
        y = data[i, 1]
        sum_of_squares += (y-(m*x + b))**2
    return sum_of_squares/len(data)

def gradient(m, b, data):
    m_final = 0
    b_final = 0
    N = len(data)
    for i in range(len(data)):
        x = data[i, 0]
        y = data[i, 1]
        b_final += -(2/N)*(y-(m*x+b))
        m_final += -(2/N)*x*(y-(m*x+b))
    return m_final, b_final

def gradient_descent(m, b, iterations, learning_rate, data):
    for i in range(iterations):
        m_final, b_final = gradient(m, b, data)
        m = m - (learning_rate*m_final)
        b = b - (learning_rate*b_final)
    return m, b

def start():
    pdata = pd.read_csv("../datasets/lactic.csv", usecols=['X', 'Y'])
    pdata = np.array(pdata)

    #learning conditions
    learning_rate = 0.001
    iterations = 1000

    #equation mx + b
    m0 = 0            #initial values of coefficients
    b0 = 0

    input_val = []
    output_val = []
    for i in range(len(pdata)):
        input_val.append(pdata[i,0])
        output_val.append(pdata[i,1])

    print("Initial value of coefficients y=mx+b:\n "
          "m = {0} b = {1} and error is {2} \n".format(m0, b0, error(m0, b0, pdata)))

    print("Gradient descent...\n")
    m, b = gradient_descent(m0, b0, iterations, learning_rate, pdata)

    print("Final value of coefficients y=mx+b:\n "
          "m = {0} b = {1} and error is {2}".format(m, b, error(m, b, pdata)))

    #not the best way to represent fit line
    #representation of linear regression results
    y_vals = [m*x+b for x in range(20)]
    x_vals = range(20)

    plt.scatter(input_val, output_val)
    plt.xlabel("Input")
    plt.ylabel("Output")
    plt.plot(x_vals, y_vals,color='blue', linewidth = 3)
    plt.show()

if __name__ == '__main__':
    start()


from numpy import array, zeros, float, dot
from copy import copy

def GaussJordan(A,b):

    n,m = A.shape
    C = zeros((n,m+1),float)
    C[:,0:n],C[:,n] = A, b

    for j in range(n):
        # partial pivoting.
        p = j
        # look for alternate pivot by searching for largest element in column
        for i in range(j+1,n):
            if abs(C[i,j]) > abs(C[p,j]): p = i
        if abs(C[p,j]) < 1.0e-16:
            print "matrix is singular" # its determinant is 0.
            return b
        # swap rows to get largest magnitude element on the diagonal
        C[p,:],C[j,:] = copy(C[j,:]),copy(C[p,:])

        pivot = C[j,j]
        C[j,:] = C[j,:] / pivot
        for i in range(n):
            if i == j: continue
            C[i,:] = C[i,:] - C[i,j]*C[j,:]
    I,x = C[:,0:n],C[:,n]
    return x


from sympy import ( symbols, solve, diff, integrate, exp, sqrt, lambdify, Integral, ln, pprint, oo )

# The clotting time of blood (in seconds) is a random variable with probability density function defined by

x = symbols( 'x' )
F = 1 / ( ln( 27 ) * x )

# for x in [1, 27].

a, b = 1, 27

def expected_value( f, var, a, b ):
	return integrate( var * f, ( var, a, b ) )

def variance( f, var, a, b, mu ):
	return integrate( ( ( var **2 ) * f ), ( var, a, b ) ) - mu**2

def std_dev( var ):
	return sqrt( var )

def expected_value( f, var, a, b ):
	return integrate( var * f, ( var, a, b ) )

mu = round( expected_value( F, x, a, b ).evalf(), 2 )
mu

# Find the standard deviation of the distribution.
var = round( variance( F, x, a, b, mu ).evalf(), 2 )
var

stdev = round( std_dev( var ), 2 )
stdev

# ind the probability that the value of the random variable is within one standard deviation of the mean.
prob_within_1sd = integrate( F, ( x, mu - stdev, mu + stdev ) )
round( prob_within_1sd.evalf(), 2 )

# Find the median clotting time.
mean = exp( ( ln( 27 ) /2 ).evalf() )
round( mean, 2 )


"""
 Purpose: The main purpose is to demonstrate how to find the running median, mode and
          mean over a sequence (list) of integers or reals or a mix of integers and reals.
          The secondary purpose, is to inspire Python programmers to explore some of
          the powerful packages (e.g. collections) available to the Python community and
          to learn more about list comprehension and lambda functions.
    Note:
       1. Much of the code here has been taken from code posted to the web (e.g. stackoverflow)
          by other Python programmers (e.g. Peter Otten)

  Author: V. Stokes (vs@it.uu.se)
 Version: 2013.03.06

"""
import numpy as np

#*******************************************************

from collections import deque,Counter
from bisect import insort, bisect_left
from itertools import islice

def RunningMode(seq,N,M):
    """
    Purpose: Find the mode for the points in a sliding window as it
             is moved from left (beginning of seq) to right (end of seq)
             by one point at a time.
     Inputs:
          seq -- list containing items for which a running mode (in a sliding window) is
                 to be calculated
            N -- length of sequence
            M -- number of items in window (window size) -- must be an integer > 1
     Otputs:
        modes -- list of modes with size M - N + 1
       Note:
         1. The mode is the value that appears most often in a set of data.
         2. In the case of ties it the last of the ties that is taken as the mode (this
            is not by definition).
    """
    # Load deque with first window of seq
    d = deque(seq[0:M])

    modes = [Counter(d).most_common(1)[0][0]]  # contains mode of first window

    # Now slide the window by one point to the right for each new position (each pass through
    # the loop). Stop when the item in the right end of the deque contains the last item in seq
    for item in islice(seq,M,N):
        old = d.popleft()                      # pop oldest from left
        d.append(item)                         # push newest in from right
        modes.append(Counter(d).most_common(1)[0][0])
    return modes

def RunningMedian(seq, M):
    """
     Purpose: Find the median for the points in a sliding window (odd number in size)
              as it is moved from left to right by one point at a time.
      Inputs:
            seq -- list containing items for which a running median (in a sliding window)
                   is to be calculated
              M -- number of items in window (window size) -- must be an integer > 1
      Otputs:
         medians -- list of medians with size N - M + 1
       Note:
         1. The median of a finite list of numbers is the "center" value when this list
            is sorted in ascending order.
         2. If M is an even number the two elements in the window that
            are close to the center are averaged to give the median (this
            is not by definition)
    """
    seq = iter(seq)
    s = []
    m = M // 2

    # Set up list s (to be sorted) and load deque with first window of seq
    s = [item for item in islice(seq,M)]
    d = deque(s)

    # Simple lambda function to handle even/odd window sizes
    median = lambda : s[m] if bool(M&1) else (s[m-1]+s[m])*0.5

    # Sort it in increasing order and extract the median ("center" of the sorted window)
    s.sort()
    medians = [median()]

    # Now slide the window by one point to the right for each new position (each pass through
    # the loop). Stop when the item in the right end of the deque contains the last item in seq
    for item in seq:
        old = d.popleft()          # pop oldest from left
        d.append(item)             # push newest in from right
        del s[bisect_left(s, old)] # locate insertion point and then remove old
        insort(s, item)            # insert newest such that new sort is not required
        medians.append(median())
    return medians

def RunningMean(seq,N,M):
    """
     Purpose: Find the mean for the points in a sliding window (fixed size)
              as it is moved from left to right by one point at a time.
      Inputs:
          seq -- list containing items for which a mean (in a sliding window) is
                 to be calculated (N items)
            N -- length of sequence
            M -- number of items in sliding window
      Otputs:
        means -- list of means with size N - M + 1

    """
    # Load deque (d) with first window of seq
    d = deque(seq[0:M])
    means = [np.mean(d)]             # contains mean of first window
    # Now slide the window by one point to the right for each new position (each pass through
    # the loop). Stop when the item in the right end of the deque contains the last item in seq
    for item in islice(seq,M,N):
        old = d.popleft()            # pop oldest from left
        d.append(item)               # push newest in from right
        means.append(np.mean(d))     # mean for current window
    return means

#*** Start of test area *****************************************************
#
# Set random seed for repeatability
#np.random.seed(7919) # the 1000th prime number

# Try the following sequences
#yn = np.random.random(18)*10 - 5
yn = [3,2,-1.0,2.0,3.0,5.0,-5.0,6.0,-5.0,4.0,9.0,6.3,1.3,0.0,-7.0,1.3,-5.0]
#yn = [3,2,-1.0,-1.0,-1.0,5.0,5.0]
#yn = [5,5.0,5,5.0,5]
#yn = [3,3,3,3,3,3,3]
#yn = [3.,3.,3.,3.,3.,3.,3.]
#yn = [-1,1,-1,1,-1,1]
#yn = [3,2,-1.0,2.0]
#yn = [5,3,2,2,-1]
#yn = [-5.0,3.0,2.0,2.0,-1.0]

N = len(yn)

# Try the follwing window sizes
#M = 1
#M = 2
M = 3
#M = 4
#M = 5
#M = 6
if M <= N and M >= 1:
    print 'M = %2d,'%M,
    print 'yn:'
    print yn

    means = RunningMean(yn,N,M)
    print ' Means(%d):' %(N-M+1)
    print means

    medians = RunningMedian(yn,M)
    print ' Medians(%d):' %(N-M+1)
    print medians

    modes = RunningMode(yn,N,M)
    print ' Modes(%d):' %(N-M+1)
    print modes
else:
    print 'Window size (M=%d) out of range'%M


import numpy as np
from pyai.loss.base import BaseLoss
from pyai import Tensor

class MSELoss(BaseLoss):
    """
    Mean-Squared Error, or L2 loss.

    Equation: MSE = \frac{\sum_{i=1}^{n}(y_{true}-y_{predicted})^2}{n}
    """

    def loss(self, y_true: Tensor, y_predicted: Tensor) -> Tensor:
        return np.mean(np.square(y_true - y_predicted))

    def gradients(self, y_true: Tensor, y_predicted: Tensor) -> Tensor:
        """
        Equation: \frac{d_{loss}}{d_{y\_predicted}}
        """
        return (y_true - y_predicted) * 2

if __name__ == "__main__":
    criterion = MSELoss()
    a = np.array([2.2, 3])
    b = np.array([1.8, 4])
    loss = criterion(a, b)
    gradients = criterion.gradients(a, b)
    gradients_lim = criterion.gradients_lim(a, b)
    print(loss, loss.shape)
    print(gradients, gradients.shape)
    print(gradients_lim, gradients_lim.shape)


"""
Author: Ali Hajimirza (ali@alihm.net)
Copyright Ali Hajimirza, free for use under MIT license.
"""
import numpy as np

# Exponent function for estimating e
exponent_func = np.vectorize(lambda x, std: np.exp((-1.0*x)/(2 * std)))

# Performs the E step give a list of x values, a list of means and a matrix of estimated values
def E_step(x_list, mean_list, e_matrix):
	# Compute the standard deviation
	std_list = get_std(x_list, mean_list, e_matrix)
	estimated = list()
	for i,std in enumerate(std_list):
		estimated.append(exponent_func(np.square(x_list - mean_list[i]), std))
	# Calculating denominator
	estimated = np.array(estimated).transpose()
	for i, n in enumerate(estimated):
		estimated[i] /= n.sum()
	return estimated

# Performs the M step give a list of x values, a list of means
def M_step(x_list, e_matrix):
	# Calculating numerator
	numerator = np.dot(x_list, e_matrix)
	# Calculating denominator
	denominator = e_matrix.sum(axis=0)
	return np.divide(numerator, denominator)

# Compute the standard deviation
def get_std(x_list, mean_list, e_matrix):
	x_vector = x_list[np.newaxis].transpose()
	var = np.square(mean_list - x_vector) * e_matrix
	return np.sqrt(var.sum(axis=0)/e_matrix.sum(axis=0))

# Computes theta
def get_theta(e_matrix):
	return e_matrix.sum(axis=0) / len(e_matrix)

# Performs E-M for a number of steps
def simulate_E_M(x_list, e_matrix ,steps):
	mean_matrix = list()
	for i in xrange(steps):
		mean_list = M_step(x_list, e_matrix)
		mean_matrix.append(mean_list)
		e_matrix  = E_step(x_list, mean_list, e_matrix)
	return np.array(mean_matrix).transpose()


# Disable debbuging logs (to get rid of cuda warnings)
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

import numpy as np

'''
Using the convolution operation between two arrays.
Check: the equation of convultion
'''
# h = [2, 1, 0]
# x = [3, 4, 5]

# y = np.convolve(x, h)
# print(y); # [6, 11, 14, 5, 0]

'''
Now we will experimante with methods of applying a kernel on the matrix.
'''

# 1) Padding(full) method

'''
Think of the kernel as a sliding window.
We have to come with the solution of padding zeros
on the input array. This is a very famous implementation and
will be easier to show how it works with a simple example
'''

# import numpy as np

# x = [6, 2]
# h = [1, 2, 5, 4]

# y = np.convolve(x, h, "full")  #now, because of the zero padding, the final dimension of the array is bigger
# print(y) # 6 14 34 34 8

# 2) Padding (same)

'''
In this approach, we just add the zero to the left (and top of the matrix in 2D).
That is, only the first 4 steps of "full" method.
'''

import numpy as np

# x = [6, 2]
# h = [1, 2, 5, 4]

# y = np.convolve(x, h, "same")  # it is same as zero padding, but with returns an ouput with the same length as max of x or h
# print(y) # 6 14 34 34

# 3) No padding (valid)

'''
In the last case we only applied the kernel when we had
a comptaible position on the h array, in some cases you
want a dimensionality reduction. For this purpose, we ignore the
steps that would need padding (zeros before and after the array)
'''

x = [6, 2]
h = [1, 2, 5, 4]

y = np.convolve(x, h, "valid")
print(y) # 14 34 34

'''
Valid returns output of length max(x, h) - min(x, h) + 1
This is to ensure that values outside of the boundary of 'h'
will not be used in the calculation of the convultion.
In the next example we will understand why we used the argument valid.
'''


import numpy as np
from checker.fault import get_fault

np.set_printoptions(suppress=True)

def seidel(matrix_a: list, vector_b: list, vector_x: list) -> list:
    """
    Seidel algorithm part
    :param matrix_a: start matrix
    :param vector_b: start vector
    :param vector_x: solution vector
    :return:
    """
    x_ = vector_x.copy()
    n = len(matrix_a)
    for j in range(0, n):
        d = vector_b[j]

        for i in range(0, n):
            if j != i:
                d -= matrix_a[j][i] * x_[i]
        x_[j] = d / matrix_a[j][j]
    return x_

def solve(matrix_a: list, vector_b: list, vector_x: list, eps=10 ** (-6)) -> list:
    """
    Main function
    :param matrix_a: start matrix
    :param vector_b: start vector
    :param vector_x: solution vector
    :param eps: epsilon for comparing
    :return:
    """
    iterations = 0
    tmp = 0
    while True:
        errors = []
        new_x = seidel(matrix_a, vector_b, vector_x)
        for i in range(len(vector_x)):
            errors.append(abs(new_x[i] - vector_x[i]))
        vector_x = new_x
        if max(errors) < eps:
            print(f'Last result: {vector_x}')
            break
        else:
            if tmp < 3:
                print(f'Temporary result: {vector_x}')
                tmp += 1
            print(f'Residual vector: {np.matrix(np.subtract(vector_b, np.dot(matrix_a, vector_x)), float)}')
            iterations += 1
    print(f'Iterations: {iterations}')
    return vector_x

a = [[4.4944, 0.1764, 1.7956, 0.7744],
     [0.1764, 15.6025, 3.4969, 0.1849],
     [1.7956, 3.4969, 8.8804, 0.2116],
     [0.7744, 0.1849, 0.2116, 19.7136]]
b = [31.97212, 9.18339, 19.51289, 51.39451]
x = [0 for _ in range(len(a[0]))]
x = solve(a.copy(), b.copy(), x.copy())
print(f'Our solution: {x}')
x_np = np.linalg.solve(a, b)
print(f'NumPy solution: {x_np}')
print(f'Residual vector: {np.matrix(np.subtract(b, np.dot(a, x)), int)}')
print(f'Residual vector for NumPy: {np.matrix(np.subtract(b, np.dot(a, x_np)), int)}')
print('Fault:', round(get_fault(x, x_np), 6))


from Tests00Data import *
from scipy import stats
import statistics
import timeit

# https://docs.python.org/3/library/statistics.html

#==================================================================================
# Arrange
print ("data          = ", data)

start = timeit.default_timer()
# Act
mean_arithmetic = statistics.mean(data)
end = timeit.default_timer()
# Assert
print ("mean_arithmetic = ", mean_arithmetic)
print (u"      time [\u00B5s] = ", (end - start) * 100000)
#assert(mean_arithmetic == 3.8)
#==================================================================================

mean_harmonic = stats.hmean(data)
print ("mean_harmonic   = ", mean_harmonic)

mean_arithmetic = statistics.mean(data)
print ("mean_arithmetic = ", mean_arithmetic)

mean_harmonic = stats.hmean(data)
print ("mean_harmonic   = ", mean_harmonic)

mode = statistics.mode(data)
print ("mode  = ", mode)

median = statistics.median(data)
print ("median          = ", median)

median_low = statistics.median_low(data)
print ("median_low      = ", median_low)

median_high = statistics.median_high(data)
print ("median_high     = ", median_high)

median_grouped = statistics.median_grouped(data)
print ("median_grouped  = ", median_grouped)


#----------------------------- Numpy > Arrays ----------------------------------

import numpy

def arrays(arr):
    a = numpy.array(arr,float)
    return numpy.flip(a)

arr = input().strip().split(' ')
result = arrays(arr)
print(result)

#----------------------------- Numpy > Shape and Reshape -----------------------

import numpy

arr = numpy.array(list(map(int, input().split())))
print(numpy.reshape(arr, (3, 3)))

#----------------------------- Numpy > Transpose and Flatten -------------------

import numpy

n, m = map(int, input().split())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
arr = numpy.array(lst)
print(numpy.transpose(arr))
print(arr.flatten())

#----------------------------- Numpy > Concatenate -----------------------------

import numpy

n, m, p = map(int, input().split())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
a = numpy.array(lst)
lst = []
for _ in range(m):
    lst.append(list(map(int, input().split())))
b = numpy.array(lst)
print(numpy.concatenate((a, b), axis = 0))

#----------------------------- Numpy > Zeros and Ones --------------------------

import numpy

axis = tuple(map(int, input().split()))
print(numpy.zeros(axis, dtype = numpy.int))
print(numpy.ones(axis, dtype = numpy.int))

#----------------------------- Numpy > Eye and Identity ------------------------

import numpy

n, m = map(int, input().split())
a = numpy.eye(n, m)
print(str(a).replace('1',' 1').replace('0',' 0')) #Otherwise the website wouldn't accept it!

#----------------------------- Numpy > Array Mathematics -----------------------

import numpy

n, m = map(int, input().split())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
a = numpy.array(lst)
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
b = numpy.array(lst)
print(a+b)
print(a-b)
print(a*b)
print(a//b)
print(a%b)
print(a**b)

#----------------------------- Numpy > Floor, Ceil and Rint --------------------

import numpy

numpy.set_printoptions(sign=' ') #Just for website's sake
a = numpy.array(list(map(float, input().split())))
print(numpy.floor(a))
print(numpy.ceil(a))
print(numpy.rint(a))

#----------------------------- Numpy > Sum and Prod ----------------------------

import numpy

n, m = map(int, input().split())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
arr = numpy.array(lst)
print(numpy.prod(numpy.sum(arr, axis = 0)))

#----------------------------- Numpy > Min and Max -----------------------------

import numpy

n, m = map(int, input().split())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
arr = numpy.array(lst)
print(numpy.max(numpy.min(arr, axis = 1)))

#----------------------------- Numpy > Mean, Var, and Std ----------------------

import numpy

numpy.set_printoptions(legacy='1.13') #Same here
n, m = map(int, input().split())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
arr = numpy.array(lst)
print(numpy.mean(arr, axis = 1))
print(numpy.var(arr, axis = 0))
print(numpy.std(arr))

#----------------------------- Numpy > Dot and Cross ---------------------------

import numpy

n = int(input())
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
a = numpy.array(lst)
lst = []
for _ in range(n):
    lst.append(list(map(int, input().split())))
b = numpy.array(lst)
print(numpy.dot(a, b))

#----------------------------- Numpy > Inner and Outer -------------------------

import numpy

a = numpy.array(list(map(int, input().split())))
b = numpy.array(list(map(int, input().split())))
print(numpy.inner(a, b))
print(numpy.outer(a, b))

#----------------------------- Numpy > Polynomials -----------------------------

import numpy

coe = list(map(float, input().split()))
print(numpy.polyval(coe, int(input())))

#----------------------------- Numpy > Linear Algebra --------------------------

import numpy

n = int(input())
lst = []
for _ in range(n):
    lst.append(list(map(float, input().split())))
arr = numpy.array(lst)
print(round(numpy.linalg.det(arr), 2))

#----------------------------- Standardize Mobile Number Using Decorators ------

import re

def wrapper(f):
    def fun(l):
        # complete the function
        for i in range(len(l)):
            m = re.match(r"(0|91|\+91)?(\d{5})(\d{5})", l[i])
            l[i] = "+91 "+ m.groups()[1] + " " + m.groups()[2]
        ret = f(l)
        return ret
    return fun

#----------------------------- Decorators 2 - Name Directory -------------------

import operator

def person_lister(f):
    def inner(people):
        for i in range(len(people)):
            people[i][2] = int(people[i][2])
        people.sort(key=lambda x: x[2])
        for i in range(len(people)):
            people[i] = f(people[i])
        return(iter(people))
    return inner

@person_lister
def name_format(person):
    return ("Mr. " if person[3] == "M" else "Ms. ") + person[0] + " " + person[1]

if __name__ == '__main__':
    people = [input().split() for i in range(int(input()))]
    print(*name_format(people), sep='\n')

#--------------------------- Birthday Cake Candles -----------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the birthdayCakeCandles function below.
def birthdayCakeCandles(ar):
    m = max(ar)
    c = 0
    for element in ar:
        if element == m:
            c += 1
    return c

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    ar_count = int(input())

    ar = list(map(int, input().rstrip().split()))

    result = birthdayCakeCandles(ar)

    fptr.write(str(result) + '\n')

    fptr.close()

#-------------------------- Kangaroo -------------------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the kangaroo function below.
def kangaroo(x1, v1, x2, v2):
    if v1 == v2:
        if x1 == x2:
            return "YES"
        else:
            return "NO"
    t = (x2 - x1)/(v1 - v2)
    if t >= 0 and t == int(t) :
        return "YES"
    else:
        return "NO"

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    x1V1X2V2 = input().split()

    x1 = int(x1V1X2V2[0])

    v1 = int(x1V1X2V2[1])

    x2 = int(x1V1X2V2[2])

    v2 = int(x1V1X2V2[3])

    result = kangaroo(x1, v1, x2, v2)

    fptr.write(result + '\n')

    fptr.close()

#-------------------------- Viral/Strange Advertising --------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the viralAdvertising function below.
def viralAdvertising(n):
    shared = 5
    likes = 0
    cumulative = 0
    for i in range(n):
        likes = shared//2
        cumulative += likes
        shared = likes*3
    return cumulative

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    n = int(input())

    result = viralAdvertising(n)

    fptr.write(str(result) + '\n')

    fptr.close()

#------------------------- Recursive Digit Sum ---------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the superDigit function below.
def superDigit(n, k):
    if len(n)*k == 1:
        return int(n)
    else:
        sums = 0
        for i in range(len(n)):
            sums += int(n[i])
        return superDigit(str(sums*k), 1)

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    nk = input().split()

    n = nk[0]

    k = int(nk[1])

    result = superDigit(n, k)

    fptr.write(str(result) + '\n')

    fptr.close()

#------------------------- Insertion Sort - Part 1 -----------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

# Complete the insertionSort1 function below.
def insertionSort1(n, arr):
    n -= 1
    x = arr[n]
    while n > 0 and x < arr[n-1]:
        arr[n] = arr[n-1]
        n -= 1
        print(*arr)
    arr[n] = x
    print(*arr, end=" ")

if __name__ == '__main__':
    n = int(input())

    arr = list(map(int, input().rstrip().split()))

    insertionSort1(n, arr)

#------------------------ Insertion Sort - Part 2 ------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

def insertionSort1(n1, arr):

    n1 -= 1
    x = arr[n1]
    while n1 > 0 and x < arr[n1-1]:
        arr[n1] = arr[n1-1]
        n1 -= 1
    arr[n1] = x
    print(*arr)
    return arr
# Complete the insertionSort2 function below.
def insertionSort2(n, arr2):
    #print(arr)
    if n == 1:
        return arr2
    else:
        #print("before call : " , []+[arr2[n-1]])
        return insertionSort1(n, insertionSort2(n-1, arr2))# + [arr2[n-1]])

if __name__ == '__main__':
    n = int(input())

    arr = list(map(int, input().rstrip().split()))

    insertionSort2(n, arr)

#----------------------------- Exceptions --------------------------------------

t = int(input())
for i in range(t):
    a, b = input().split()
    try:
        print(int(a)//int(b))
    except Exception as e:
        print("Error Code:",e)

#---------------------------- XML 1 - Find the Score ---------------------------

import sys
import xml.etree.ElementTree as etree

def get_attr_number(node):
    s = 0
    for child in node:
        s += get_attr_number(child)
    s += len(node.attrib)
    return s

if __name__ == '__main__':
    sys.stdin.readline()
    xml = sys.stdin.read()
    tree = etree.ElementTree(etree.fromstring(xml))
    root = tree.getroot()
    print(get_attr_number(root))

#-------------------------- XML2 - Find the Maximum Depth ----------------------

import xml.etree.ElementTree as etree

maxdepth = 0
def depth(elem, level):
    global maxdepth
    level += 1
    for child in elem:
        depth(child, level)
    if level > maxdepth:
        maxdepth = level

if __name__ == '__main__':
    n = int(input())
    xml = ""
    for i in range(n):
        xml =  xml + input() + "\n"
    tree = etree.ElementTree(etree.fromstring(xml))
    depth(tree.getroot(), -1)
    print(maxdepth)

#----------------- Regex > Detect Floating Point Number ------------------------

import re

for i in range(int(input())):
    print(bool(re.match(r"\A[+-0123456789]\d*\.\d+\Z", input())))

#----------------- Regex > Re.split() ------------------------------------------

regex_pattern = r"\W"	# Do not delete 'r'.
import re
print("\n".join(re.split(regex_pattern, input())))

#----------------- Regex > Group(), Groups() & Groupdict() ---------------------

import re

m = re.match(r'.*?([a-zA-Z0-9])\1', input())
if m == None:
    print(-1)
else:
    print(m.group(1))

#----------------- Regex > Re.findall() & Re.finditer() ------------------------

import re
lst = re.findall(r"(?<=[QWRTYPSDFGHJKLZXCVBNMqwrtypsdfghjklzxcvbnm])([AEIOUaeiou][AEIOUaeiou]+)(?=[QWRTYPSDFGHJKLZXCVBNMqwrtypsdfghjklzxcvbnm])", input())
if lst == []:
    print(-1)
else:
    for item in lst:
        print(item)

#----------------- Regex > Re.start() & Re.end() -------------------------------

import re

s = input()
k = input()
match_objects = re.finditer(r''+ k[0] + '(?='+ k[1:] +')',s)
lst = list(map(lambda x: x.start(),match_objects))
if lst == []:
    print((-1, -1))
else:
    for item in lst:
        print((item, item + len(k) -1))

#----------------- Regex > Regex Substitution ----------------------------------

import re

n = int(input())
for _ in range(n):
    s = input()
    s = re.sub(r"(?<=\s)\|\|(?=\s)", "or" , s)
    s = re.sub(r"(?<=\s)&&(?=\s)", "and" , s)
    print(s)

#----------------- Regex > Validating Roman Numerals ---------------------------

regex_pattern = r"^(I(?=X))?(X(?=C))?(C(?=M))?M{0,3}(I(?=X))?(X(?=C))?(C(?=M))?((?<=C|X|I)M)?(I(?=X))?(X(?=C))?(C(?=D))?D?(I(?=X))?(X(?=C))?C{0,3}(I(?=X))?(X(?=L))?L?(I(?=X))?X{0,3}(I(?=V))?V?I{0,3}$"	# Do not delete 'r'.

import re
print(str(bool(re.match(regex_pattern, input()))))
    # Only one I, X, and C can be used as the leading numeral in part of a subtractive pair.
    # I can only be placed before V and X.
    # X can only be placed before L and C.
    # C can only be placed before D and M.

    # Five in a row of any digit is not allowed
    # Some digits are allowed in runs of up to 4. They are I,X,C, and M. The others (V,L,D) can only appear singly.
    # Some lower digits can come before a higher digit, but only if they appear singly. E.g. "IX" is ok but "IIIX" is not.
    # But this is only for pairs of digits. Three ascending numbers in a row is invalid. E.g. "IX" is ok but "IXC" is not.
    # A single digit with no runs is always allowed

#  I can be placed before V (5) and X (10) to make 4 and 9.
#   ⋅ X can be placed before L (50) and C (100) to make 40 and 90.
#   ⋅ C can be placed before D (500) and M (1000) to make 400 and 900.

#----------------- Regex > Validating phone numbers ----------------------------

import re

for _ in range(int(input())):
    m = re.match("^[789]\d{9}$", input())
    if bool(m) == True:
        print("YES")
    else:
        print("NO")

#----------------- Regex > Validating and Parsing Email Addresses --------------

import email.utils
import re

for _ in range(int(input())):
    t = email.utils.parseaddr(input())
    if bool(re.match(r"^[a-zA-Z](\w|-|\.)+@[a-zA-Z]+\.[a-zA-Z]{1,3}$", t[1])) == True:
        print(email.utils.formataddr(t))

#----------------- Regex > Hex Color Code --------------------------------------

import re

for _ in range(int(input())):
    m = re.finditer(r"(?<!^)(#[a-fA-F0-9]{6}|#[a-fA-F0-9]{3})", input().lstrip())
    for item in list(map(lambda x: x.group(1), m)):
        print(item)

#------------------------- Regex > HTML Parser - Part 1 ------------------------

from html.parser import HTMLParser

# create a subclass and override the handler methods
class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print("Start :", tag)
        for attr in attrs:
            print("-> " + str(attr[0]) + " > " + str(attr[1]))
    def handle_endtag(self, tag):
        print("End   :", tag)
    def handle_startendtag(self, tag, attrs):
        print("Empty :", tag)
        for attr in attrs:
            print("-> " + str(attr[0]) + " > " + str(attr[1]))

s = ""
for _ in range(int(input())):
    s = s + input()
parser = MyHTMLParser()
parser.feed(s)
parser.close()

#------------------------- Regex > HTML Parser - Part 2 ------------------------

from html.parser import HTMLParser

class MyHTMLParser(HTMLParser):
    def handle_data(self, data):
        if data != "\n":
            print(">>> Data")
            print(data)
    def handle_comment(self, data):
        if data.find("\n") == -1:
            print(">>> Single-line Comment")
        else:
            print(">>> Multi-line Comment")
        print(data)

html = ""
for i in range(int(input())):
    html += input().rstrip()
    html += '\n'

parser = MyHTMLParser()
parser.feed(html)
parser.close()

#----------------- Regex > Detect HTML Tags, Attributes and Attribute Values ---

import re

s = ""
for _ in range(int(input())):
    s += input()
s = re.sub(r"<!--.*?-->", "", s)
m = re.findall(r"<.+?>|</.+?>|<.+?/>", s)
for item in m:
    if re.match(r"</.+>", item): #---------------------- End
        continue
    elif re.match(r"<.+/>", item): #-------------------Empty
        m = re.search(r"^<\s*?(\S*)", item)
        print(m.group(1)) #--- Print the tag and then remove it
        #print(item[m.end():-2])
        f = re.finditer(r"(\S+)\s*=\s*\"(.*?)\"|(\S+)\s*=\s*\'(.*?)\'|(\S+)", item[m.end():-2])
        if f != None:
            lst = list(map(lambda x : x.groups(), f))
            #print(lst)
            for element in lst:
                if element[0] == None and element[2] == None: #---- No Value
                    print("-> " + element[4] + " > None")
                elif element[0] == None and element[4] == None: #--- With ''
                    print("-> " + element[2] + " > " + element[3])
                elif element[2] == None and element[4] == None: #--- With ""
                    print("-> " + element[0] + " > " + element[1])
    elif re.match(r"<.+>", item): #---------------------Start
        m = re.search(r"^<\s*?(\S*)", item)
        if m.end() == len(item): #--- Print the tag and then remove it
            print(m.group(1)[:-1])
        else:
            print(m.group(1)) #---- if it has attrs ">" will be at the end
        f = re.finditer(r"(\S+)\s*=\s*\"(.*?)\"|(\S+)\s*=\s*\'(.*?)\'|(\S+)", item[m.end():-1])
        if f != None:
            lst = list(map(lambda x : x.groups(), f))
            #print(lst)
            for element in lst:
                if element[0] == None and element[2] == None: #--- No Value
                    print("-> " + element[4] + " > None")
                elif element[0] == None and element[4] == None: #--- With ''
                    print("-> " + element[2] + " > " + element[3])
                elif element[2] == None and element[4] == None: #--- With ""
                    print("-> " + element[0] + " > " + element[1])

#------------------------- Regex > Validating UID ------------------------------

import re

for _ in range(int(input())):
    s = input()
    flag = True
    if re.match(r"^[a-zA-Z0-9]{10}$", s) == None:
        flag = False
    m = re.findall(r"([\w*]).*\1", s)
    if m != []:
        flag = False
    m = re.findall(r"[A-Z]", s)
    if len(m) < 2:
        flag = False
    m = re.findall(r"[0-9]", s)
    if len(m) < 3:
        flag = False

    if flag == True:
        print("Valid")
    else:
        print("Invalid")

#------------------------ Regex > Validating Credit Card Numbers ---------------

import re

for _ in range(int(input())):
    c = input()
    if re.match(r"^[456]\d{3}-?\d{4}-?\d{4}-?\d{4}$", c) and re.findall(r"(\d)-?\1-?\1-?\1", c) == []:
        print("Valid")
    else:
        print("Invalid")

#------------------------ Regex > Validating Postal Codes ----------------------

regex_integer_in_range = r"^[1-9]\d{5}$"	# Do not delete 'r'.
regex_alternating_repetitive_digit_pair = r"(\d)(?=.\1)"	# Do not delete 'r'.

import re
P = input()

print (bool(re.match(regex_integer_in_range, P))
and len(re.findall(regex_alternating_repetitive_digit_pair, P)) < 2)

#------------------------ Regex > Matrix Script --------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

first_multiple_input = input().rstrip().split()
n = int(first_multiple_input[0])
m = int(first_multiple_input[1])
matrix = []
for _ in range(n):
    matrix_item = input()
    matrix.append(matrix_item)
columns = zip(*matrix)
l = []
for col in columns:
    l += list(col)
s = ''.join(l)
print(re.sub(r"(?<=[a-zA-Z0-9])([!@#$%&]|\s)+(?=[a-zA-Z0-9])", " ", s))

#------------------------- Map and Lambda Function -----------------------------

cube = lambda x: x**3 # complete the lambda function

def fibonacci(n):
    # return a list of fibonacci numbers
    l = []
    for i in range(n):
        if i == 0 :
            l.append(0)
        elif i == 1:
            l.append(1)
        else:
            l.append(l[i-1]+l[i-2])
    return l

if __name__ == '__main__':
    n = int(input())
    print(list(map(cube, fibonacci(n))))

#------------------------- Zipped! ---------------------------------------------

import statistics
n, x = map(int, input().split())
mark_sheet = []
for i in range(x):
    lst = list(map(float, input().split()))
    mark_sheet.append(lst)
zipped = zip(*mark_sheet)
for item in zipped:
    print(statistics.mean(item))

#------------------------- Athlete Sort ---------------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

if __name__ == '__main__':
    nm = input().split()

    n = int(nm[0])

    m = int(nm[1])

    arr = []

    for _ in range(n):
        arr.append(list(map(int, input().rstrip().split())))

    k = int(input())
    #print(arr)
    arr = sorted(arr, key = lambda x : x[k])
    #print(arr)
    for i in range(n):
        for j in range(m):
            print(arr[i][j], end = " ")
        print("")

#------------------------- ginortS ---------------------------------------------

s = input()
lc = []
uc = []
od = []
ed = []
for i in range(len(s)):
    if s[i].isdigit():
        if int(s[i])% 2 == 0:
            ed.append(s[i])
        else:
            od.append(s[i])
    elif s[i].islower():
        lc.append(s[i])
    elif s[i].isupper():
        uc.append(s[i])
out = ""
lc.sort()
uc.sort()
od.sort()
ed.sort()
for item in lc:
    out += item
for item in uc:
    out += item
for item in od:
    out += item
for item in ed:
    out += item
print(out)

#------------------------- Calendar Module -------------------------------------

import calendar

m, d, y = map(int, input().split())
i = calendar.weekday(y, m, d)
l = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY", "SATURDAY", "SUNDAY"]
print(l[i])

#------------------------- Time Delta ------------------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys
from datetime import datetime, timezone
# Complete the time_delta function below.
def time_delta(t1, t2):
    tmp = t1.split()
    t1_dt = datetime.strptime(' '.join(tmp[1:]), '%d %b %Y %H:%M:%S %z')
    t1_dt_utc = t1_dt.astimezone(tz = timezone.utc)
    tmp = t2.split()
    t2_dt = datetime.strptime(' '.join(tmp[1:]), '%d %b %Y %H:%M:%S %z')
    t2_dt_utc = t2_dt.astimezone(tz = timezone.utc)
    return str(abs((t1_dt_utc - t2_dt_utc).days * 24 * 3600 + (t1_dt_utc - t2_dt_utc).seconds))

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    t = int(input())

    for t_itr in range(t):
        t1 = input()

        t2 = input()

        delta = time_delta(t1, t2)

        fptr.write(delta + '\n')

    fptr.close()

#------------------------- collections.Counter() -------------------------------

from collections import Counter
x = int(input())
shoes = list(map(int, input().split()))
c = Counter(shoes)
earnings = 0
for i in range(int(input())):
    size, price = map(int, input().split())
    if c[size] > 0:
        c[size] -= 1
        earnings += price
print(earnings)

#------------------------- DefaultDict Tutorial --------------------------------

from collections import defaultdict
n, m = map(int, input().split())
a = defaultdict(list)
b = []
for i in range(n):
    a[input()].append(i+1)
for i in range(m):
    item = input()
    if a[item] == []:
        a[item].append(-1)
    print(" ".join(map(str,a[item])))

#------------------------- Collections.namedtuple() ----------------------------

from collections import namedtuple

n = int(input())
Student = namedtuple('Student', input())
students = []
for i in range(n):
    args = input().split()
    st = Student(args[0], args[1], args[2], args[3])
    students.append(st)
s = 0
for item in students:
    s += int(item.MARKS)
print(s/n)

#------------------------- Collections.OrderedDict() ---------------------------

from collections import OrderedDict
n = int(input())
od = OrderedDict()
for i in range(n):
    row = input().split()
    price = int(row[-1])
    name = ' '.join(row[:-1])
    if od.__contains__(name):
        od[name] += price
    else:
        od[name] = price
for item in od:
    print(item, od[item])

#------------------------- Word Order ------------------------------------------

from collections import OrderedDict
n = int(input())
od = OrderedDict()
for i in range(n):
    word = input()
    if od.__contains__(word):
        od[word] += 1
    else:
        od[word] = 1
print(len(od))
for item in od:
    print(od[item], end=" ")

#------------------------- Collections.deque() ---------------------------------

from collections import deque

n = int(input())
d = deque()
for i in range(n):
    command = input().split()
    if command[0] == "append":
        d.append(int(command[1]))
    elif command[0] == "appendleft":
        d.appendleft(int(command[1]))
    elif command[0] == "pop":
        d.pop()
    elif command[0] == "popleft":
        d.popleft()
for i in d:
    print(i, end = " ")

#------------------------- Company Logo ----------------------------------------

from collections import Counter

if __name__ == '__main__':
    s = input()
    c = Counter(s.replace(" ", ""))
    n = 3
    while n > 0:
        l = []
        m = max(c.values())
        for item in list(c):
            if c[item] == m:
                x = c.pop(item)
                l.append(item)
        l.sort()
        for i in l:
            if n > 0:
                print(str(i) + " " + str(m))
                n -= 1

#------------------------- Piling Up! ------------------------------------------

from collections import deque
t = int(input())
for i in range(t):
    d = deque()
    flag = True
    n = int(input())
    l = list(map(int, input().split()))
    for item in l:
        d.append(item)
    temp = 0
    if d[0] >= d[-1]:
        temp = d.popleft()
    else:
        temp = d.pop()
    for k in range(n-2):
        if d[0] >= d[-1]:
            temp2 = d.popleft()
        else:
            temp2 = d.pop()
        if(temp < temp2):
            flag = False
        temp = temp2
    if d[0] <= temp and flag == True:
        print("Yes")
    else:
        print("No")

#------------------------- Introduction to Sets --------------------------------

def average(array):
    # your code goes here
    s = set(arr)
    return sum(s)/len(s) # It's not even correct but it's what the question asks for, so...

if __name__ == '__main__':
    n = int(input())
    arr = list(map(int, input().split()))
    result = average(arr)
    print(result)

#------------------------- No Idea! --------------------------------------------

n, m = map(int, input().split())
arr = list(map(int, input().split()))
a = set(map(int, input().split()))
b = set(map(int, input().split()))
happiness = 0
for item in arr:
    if a.__contains__(item):
        happiness += 1
    elif b.__contains__(item):
        happiness -= 1
print(happiness)

#------------------------- Symmetric Difference --------------------------------

m = int(input())
set1 = set(map(int, input().split()))
n = int(input())
set2 = set(map(int, input().split()))
#sd = (set1.union(set2)).difference(set1.intersection(set2))
sd = set1.__xor__(set2)
for i in range(len(sd)):
    print(min(sd))
    sd.remove(min(sd))

#------------------------- Set .add() ------------------------------------------

n = int(input())
countries = set()
for i in range(n):
    countries.add(input())
print(len(countries))

#------------------------- Set .discard(), .remove() & .pop() ------------------

n = int(input())
s = set(map(int, input().split()))
nc = int(input())
for i in range(nc):
    command = input().split()
    if command[0] == 'pop':
        s.pop()
    elif command[0] == 'remove':
        s.remove(int(command[1]))
    elif command[0] == 'discard':
        s.discard(int(command[1]))
print(sum(s))

#------------------------- Set .union() Operation ------------------------------

input()
n = set(map(int, input().split()))
input()
b = set(map(int, input().split()))
print(len(n.union(b)))

#------------------------- Set .intersection() Operation -----------------------

input()
n = set(map(int, input().split()))
input()
b = set(map(int, input().split()))
print(len(n.intersection(b)))

#------------------------- Set .difference() Operation -------------------------

input()
e = set(map(int, input().split()))
input()
f = set(map(int, input().split()))
print(len(e-f))

#------------------------- Set .symmetric_difference() Operation ---------------

input()
e = set(map(int, input().split()))
input()
f = set(map(int, input().split()))
print(len(e^f))

#------------------------- Set Mutations ---------------------------------------

input()
a = set(map(int, input().split()))
for i in range(int(input())):
    command, n = input().split()
    s = set(map(int, input().split()))
    if command == "update":
        a.update(s)
    elif command == "intersection_update":
        a.intersection_update(s)
    elif command == "difference_update":
        a.difference_update(s)
    elif command == "symmetric_difference_update":
        a.symmetric_difference_update(s)
print(sum(a))

#------------------------- The Captain's Room ----------------------------------

k = int(input())
rnl = list(map(int, input().split()))
s = set(rnl)
print( int((sum(s)*k-sum(rnl))/(k-1)) )

#------------------------- Check Subset ----------------------------------------

for i in range(int(input())):
    input()
    a = set(map(int, input().split()))
    input()
    b = set(map(int, input().split()))
    if a.issubset(b):
        print("True")
    else:
        print("False")

#------------------------- Check Strict Superset -------------------------------

a = set(map(int, input().split()))
flag = True
for i in range(int(input())):
    s = set(map(int, input().split()))
    if not(a.issuperset(s)) or len(a) <= len(s):
        flag = False
print(flag)

#------------------------- sWAP cASE -------------------------------------------

def swap_case(s):
    swapedstr = ""
    for i in range(len(s)):
        if s[i].islower():
            swapedstr += s[i].upper()
        else:
            swapedstr += s[i].lower()
    return swapedstr

if __name__ == '__main__':
    s = input()
    result = swap_case(s)
    print(result)

#------------------------- String Split and Join -------------------------------

def split_and_join(line):
    # write your code here
    lst = line.split(" ")
    return "-".join(lst)

if __name__ == '__main__':
    line = input()
    result = split_and_join(line)
    print(result)

#------------------------- What's Your Name? -----------------------------------

def print_full_name(a, b):
    print("Hello " + a + " " + b + "! You just delved into python.")

if __name__ == '__main__':
    first_name = input()
    last_name = input()
    print_full_name(first_name, last_name)

#------------------------- Mutations -------------------------------------------

def mutate_string(string, position, character):
    return string[:position] + character + string[position+1:]

if __name__ == '__main__':
    s = input()
    i, c = input().split()
    s_new = mutate_string(s, int(i), c)
    print(s_new)

#------------------------- Find a string ---------------------------------------

def count_substring(string, sub_string):
    cnt = 0
    for i in range(len(string)-len(sub_string)+1):
        if string[i:i+len(sub_string)] == sub_string:
            cnt += 1
    return cnt

if __name__ == '__main__':
    string = input().strip()
    sub_string = input().strip()

    count = count_substring(string, sub_string)
    print(count)

#------------------------- String Validators -----------------------------------

if __name__ == '__main__':
    s = input()
    alphanum = False
    alpha = False
    dig = False
    lc = False
    uc = False
    for i in range(len(s)):
        if s[i].isalnum():
            alphanum = True
        if s[i].isalpha():
            alpha = True
        if s[i].isdigit():
            dig = True
        if s[i].islower():
            lc = True
        if s[i].isupper():
            uc = True
    print(alphanum)
    print(alpha)
    print(dig)
    print(lc)
    print(uc)

#------------------------- Text Alignment --------------------------------------

#Replace all ______ with rjust, ljust or center.

thickness = int(input()) #This must be an odd number
c = 'H'

#Top Cone
for i in range(thickness):
    print((c*i).rjust(thickness-1)+c+(c*i).ljust(thickness-1))

#Top Pillars
for i in range(thickness+1):
    print((c*thickness).center(thickness*2)+(c*thickness).center(thickness*6))

#Middle Belt
for i in range((thickness+1)//2):
    print((c*thickness*5).center(thickness*6))

#Bottom Pillars
for i in range(thickness+1):
    print((c*thickness).center(thickness*2)+(c*thickness).center(thickness*6))

#Bottom Cone
for i in range(thickness):
    print(((c*(thickness-i-1)).rjust(thickness)+c+(c*(thickness-i-1)).ljust(thickness)).rjust(thickness*6))

#------------------------- Text Wrap -------------------------------------------

import textwrap

def wrap(string, max_width):
    return textwrap.fill(string, max_width)

if __name__ == '__main__':
    string, max_width = input(), int(input())
    result = wrap(string, max_width)
    print(result)

#------------------------- Designer Door Mat -----------------------------------

n, m = input().split()
n = int(n)
m = int(m)
c = ".|."
for i in range(n//2):
    print( (c*i).rjust(int((m-3)/2), '-')+c+(c*i).ljust(int((m-3)/2), '-') )
print("WELCOME".center(m, '-'))
for i in range(n//2-1, -1, -1):
    print( (c*i).rjust(int((m-3)/2), '-')+c+(c*i).ljust(int((m-3)/2), '-') )

#------------------------- String Formatting -----------------------------------

def print_formatted(number):
    # your code goes here
    w = len(bin(number))-2
    for i in range(1, number +1):
       print(("{0:"+ str(w) +"d} {1:"+ str(w) +"o} {2:"+ str(w) +"X} {3:"+ str(w) +"b}").format(i, i, i, i))

if __name__ == '__main__':
    n = int(input())
    print_formatted(n)

#------------------------- Alphabet Rangoli ------------------------------------

import string
def print_rangoli(size):
    for i in range(size -1, -1, -1):
        s = string.ascii_lowercase[i]
        for j in range(i+1, size):
            s = string.ascii_lowercase[j] + "-" + s + "-" + string.ascii_lowercase[j]
        print(s.center(4*size -3, '-'))
    for i in range(1, size):
        s = string.ascii_lowercase[i]
        for j in range(i+1, size):
            s = string.ascii_lowercase[j] + "-" + s + "-" + string.ascii_lowercase[j]
        print(s.center(4*size -3, '-'))

if __name__ == '__main__':
    n = int(input())
    print_rangoli(n)

#------------------------- Capitalize! -----------------------------------------

# Complete the solve function below.
def solve(s):
    # l = s.split()
    # for i in range(len(l)):
    #     l[i] = l[i][0].upper() + l[i][1:]
    # return " ".join(l)
    flag = True
    for i in range(len(s)):
        if s[i] == ' ':
            flag = True
        elif flag == True:
            s = s[:i] + s[i].upper() + s[i+1:]
            flag = False
    return s

if __name__ == '__main__':
    fptr = open(os.environ['OUTPUT_PATH'], 'w')

    s = input()

    result = solve(s)

    fptr.write(result + '\n')

    fptr.close()

#------------------------- The Minion Game -------------------------------------

def minion_game(string):
    # your code goes here
    lst = ['A', 'E', 'I', 'O', 'U']
    stuart = 0
    kevin = 0
    for i in range(len(string)):
        if lst.__contains__(s[i]):
            kevin += len(string) -i
        else:
            stuart += len(string) -i
    if stuart > kevin:
        print("Stuart " + str(stuart))
    elif stuart < kevin:
        print("Kevin " + str(kevin))
    else:
        print("Draw")

if __name__ == '__main__':
    s = input()
    minion_game(s)

#------------------------- Merge the Tools! ------------------------------------

def merge_the_tools(string, k):
    # your code goes here
    n = len(string)
    s = string[0]
    for i in range(1, n):
        if i % k == 0:
            print(s)
            s = string[i]
        else:
            flag = False
            for j in range(len(s)):
                if s[j] == string[i]:
                    flag = True
            if flag == False:
                s += string[i]
    print(s)

if __name__ == '__main__':
    string, k = input(), int(input())
    merge_the_tools(string, k)

#------------------------- List Comprehensions ---------------------------------

if __name__ == '__main__':
    x = int(input())
    y = int(input())
    z = int(input())
    n = int(input())
    print([ [ i, j, k] for i in range(x + 1) for j in range(y + 1) for k in range(z + 1) if ( ( i + j + k ) != n )])

#------------------------- Find the Runner-Up Score! ---------------------------

if __name__ == '__main__':
    n = int(input())
    arr = map(int, input().split())
    ls = list(arr)
    ls.sort()
    mx = ls[-1]
    while ls[-1] == mx:
        ls = ls[:-1]
    print(ls[-1])

#------------------------- Nested Lists ----------------------------------------

if __name__ == '__main__':
    d = {}
    for _ in range(int(input())):
        name = input()
        score = float(input())
        d[name] = score
    minimum = min(d.values())
    delete = [key for key in d if d[key] == minimum]
    for key in delete:
        del d[key]
    minimum = min(d.values())
    lst = []
    for key, value in d.items():
        if value == minimum:
            lst += [key]
    lst.sort()
    for i in lst:
        print(i)

#------------------------- Finding the percentage ------------------------------

if __name__ == '__main__':
    n = int(input())
    student_marks = {}
    for _ in range(n):
        name, *line = input().split()
        scores = list(map(float, line))
        student_marks[name] = scores
    query_name = input()
    ave = sum(student_marks[query_name])/3
    print("{:.2f}".format(ave))

#------------------------- Lists -----------------------------------------------

if __name__ == '__main__':
    N = int(input())
    commands = []
    for _ in range(N):
        func, *line = input().split()
        args = list(map(int, line))
        commands += [[func, args]]
    lst = []
    for i in commands:
        if i[0] == 'insert':
            lst.insert(i[1][0], i[1][1])
        elif i[0] == 'print':
            print(lst)
        elif i[0] == 'remove':
            lst.remove(i[1][0])
        elif i[0] == 'append':
            lst.append(i[1][0])
        elif i[0] == 'sort':
            lst.sort()
        elif i[0] == 'pop':
            lst.pop()
        elif i[0] == 'reverse':
            lst.reverse()

#------------------------- Tuples ----------------------------------------------

if __name__ == '__main__':
    n = int(input())
    integer_list = map(int, input().split())
    t = tuple(integer_list)
    print(t.__hash__())

#------------------------- Say "Hello, World!" With Python ---------------------

print("Hello, World!") #Do I really need to do this? :D

#------------------------- Python If-Else --------------------------------------

#!/bin/python3

import math
import os
import random
import re
import sys

if __name__ == '__main__':
    n = int(input().strip())
    if n % 2 == 1 or ( n > 5 and n < 21 ):
        print("Weird")
    else:
        print("Not Weird")

#------------------------- Arithmetic Operators --------------------------------

if __name__ == '__main__':
    a = int(input())
    b = int(input())
    print(a+b)
    print(a-b)
    print(a*b)

#------------------------- Python: Division ------------------------------------

if __name__ == '__main__':
    a = int(input())
    b = int(input())
    print(a//b)
    print(a/b)

#------------------------- Loops -----------------------------------------------

if __name__ == '__main__':
    n = int(input())
    for i in range(n):
        print(i**2)

#------------------------- Write a function ------------------------------------

def is_leap(year):
    leap = False

    # Write your logic here
    if year % 4 == 0:
        if year % 400 == 0:
            leap = True
        elif (year % 100) == 0:
            leap = False
        else:
            leap = True

    return leap

year = int(input())
print(is_leap(year))

#------------------------- Print Function --------------------------------------

if __name__ == '__main__':
    n = int(input())
    str1 = ""
    for i in range(1, n+1):
        str1 += str(i)
    print(str1)


# calculate error
import numpy as np

# mean square error
def mean_square_error(pred, target):
    """
    Determine mean square error.
    f(y_t, y) = sum((y_t-y)**2)/n
        where, y_t = predicted value
                y  = target value
                n = number of values

    :param pred: {array}, shape(n_samples,)
            predicted values.
    :param target: {array}, shape(n_samples,)
            target values.
    :return: mean square error.
    """
    error = pred - target
    square_error = error * error
    return np.mean(square_error)

# mean absolute error
def mean_absolute_error(pred, target):
    """
    Determine mean absolute error.
    f(y_t, y) = sum(abs(y_t-y))/n
        where, y_t = predicted value
                y  = target value
                n = number of values

    :param pred: {array}, shape(n_samples,)
            predicted values.
    :param target: {array}, shape(n_samples,)
            target values.
    :return: mean absolute error.
    """
    abs_error = np.abs(pred - target)
    return np.mean(abs_error)

# mean log cosh error
def mean_log_cosh_error(pred, target):
    """
    Determine mean log cosh error.
    f(y_t, y) = sum(log(cosh(y_t-y)))/n
        where, y_t = predicted value
                y  = target value
                n = number of values

    :param pred: {array}, shape(n_samples,)
            predicted values.
    :param target: {array}, shape(n_samples,)
            target values.
    :return: mean log cosh error.
    """
    error = pred - target
    return np.mean(np.log(np.cosh(error)))

# log loss function
def log_loss(pred, target):
    """
    Determine mean log loss function.
    :param pred: {array}, shape{n_samples,}
            predicted values.
    :param target: {array}, shape{n_samples,}
            target values.
    :return: mean log loss error.
    """
    pred[pred == 0] = 0.00001
    pred[pred == 1] = 0.99999
    return -np.mean((target*np.log(pred) + (1-target)*np.log(1-pred)))

errors = {"mean_square_error": mean_square_error, "mean_absolute_error": mean_absolute_error,
          "mean_log_cosh_error": mean_log_cosh_error, "log_loss": log_loss}