"""
Compositional Data?
--------------------
"""

########################################################################################
# pyrolite comes with a few datasets from Aitchison (1984) built in which we can use
# as examples:
#
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pyrolite.plot import pyroplot
from pyrolite.data.Aitchison import load_kongite

df = load_kongite()
########################################################################################
# For compositional data, everything is relative (thanks to the closure property), so we
# tend to use ratios to express differences or changes between things. However,
# if we make incorrect assumptions about the nature of our data, we can get some incorrect
# answers. Say you want to know the average ratio between A and B:
#
A_on_B = df["A"] / df["B"]
A_on_B.mean()  # 2.8265837788402983
########################################################################################
# Equally, you could have chosen to calculate the average ratio between B and A
#
B_on_A = df["B"] / df["A"]
B_on_A.mean()  # 0.4709565704852008
########################################################################################
# You expect these to be invertable, such that A_on_B = 1 / B_on_A; but not so!
#
A_on_B.mean() / (1 / B_on_A.mean())  # 1.3311982026717262
########################################################################################
# Similarly, the relative variances are different:
#
np.std(A_on_B) / A_on_B.mean()  # 0.6295146309597085
np.std(B_on_A) / B_on_A.mean()  # 0.5020948201979953
########################################################################################
# This improves when using logratios in place of simple ratios, prior to exponentiating means
#
logA_on_B = (df["A"] / df["B"]).apply(np.log)
logB_on_A = (df["B"] / df["A"]).apply(np.log)
########################################################################################
# The logratios are invertible:
#
np.exp(logA_on_B.mean())  # 2.4213410747400514
1 / np.exp(logB_on_A.mean())  # 2.421341074740052
########################################################################################
# The logratios also have the same variance:
(np.std(logA_on_B) / logA_on_B.mean()) ** 2  # 0.36598579018127086
(np.std(logB_on_A) / logB_on_A.mean()) ** 2  # 0.36598579018127086

########################################################################################
# These peculiarities result from incorrect assumptions regarding the distribution of the
# data: ratios of compositional components are typically *lognormally* distributed, rather
# than *normally* distributed, and the compositional components themselves commonly have
# a `Poisson distribution <https://en.wikipedia.org/wiki/Poisson_distribution>`__ .
# These distributions contrast significantly with the normal distribution at the core of
# most statistical tests. We can compare distributions with similar means and variances
# but different forms, and note that the normal distribution has one immediate
# failure, in that it has non-zero probability density below 0, and we know that you can't
# have negative atoms!
#
from scipy.stats import norm, poisson, lognorm

means = [[10, 10], [10, 20], [20, 100], [1000, 50]]
fig, ax = plt.subplots(len(means), 4, figsize=(11, 8))
ax[0, 0].set_title("A")
ax[0, 1].set_title("B")
ax[0, 2].set_title("Normal Fit to B/A")
ax[0, 3].set_title("Lognormal Fit to B/A")
ax[-1, 0].set_xlabel("A")
ax[-1, 1].set_xlabel("B")
ax[-1, 2].set_xlabel("B/A")
ax[-1, 3].set_xlabel("B/A")
for ix, (m1, m2) in enumerate(means):
    p1, p2 = poisson(mu=m1), poisson(mu=m2)
    y1, y2 = p1.rvs(2000), p2.rvs(2000)
    ratios = y2[y1 > 0] / y1[y1 > 0]

    y1min, y1max = y1.min(), y1.max()
    y2min, y2max = y2.min(), y2.max()
    ax[ix, 0].hist(
        y1,
        color="0.5",
        alpha=0.6,
        label="A",
        bins=np.linspace(y1min - 0.5, y1max + 0.5, (y1max - y1min) + 1),
    )
    ax[ix, 1].hist(
        y2,
        color="0.5",
        alpha=0.6,
        label="B",
        bins=np.linspace(y2min - 0.5, y2max + 0.5, (y2max - y2min) + 1),
    )

    # normal distribution fit
    H, binedges, patches = ax[ix, 2].hist(
        ratios, color="Purple", alpha=0.6, label="Ratios", bins=100
    )
    loc, scale = norm.fit(ratios, loc=0)
    pdf = norm.pdf(binedges, loc, scale)
    twin2 = ax[ix, 2].twinx()
    twin2.set_ylim(0, 1.1 * np.max(pdf))
    twin2.plot(binedges, pdf, color="k", ls="--", label="Normal Fit")

    # log-normal distribution fit
    H, binedges, patches = ax[ix, 3].hist(
        ratios, color="Green", alpha=0.6, label="Ratios", bins=100
    )
    s, loc, scale = lognorm.fit(ratios, loc=0)
    pdf = lognorm.pdf(binedges, s, loc, scale)
    twin3 = ax[ix, 3].twinx()
    twin3.set_ylim(0, 1.1 * np.max(pdf))
    twin3.plot(binedges, pdf, color="k", ls="--", label="Lognormal Fit")

    for a in [*ax[ix, :], twin2, twin3]:
        a.set_yticks([])

plt.tight_layout()
########################################################################################
# The form of these distributions is a reflection of the fact that geochemical data
# is at is core a measure of relative quantities of atoms. Quantities of atoms have
# discrete distributions (i.e. you can have precisely 0, 1 or 6.02 x 10^23 atoms, but 1.23
# atoms is not a sensible state of affairs); if you were to count them in a shiny
# machine, the amount of atoms you might measure over a given period will have a Poisson
# distribution. If you measure two components, the probability density distribution of the
# ratio is well approximated by a lognormal distribution (note this doesn't consider
# inherent covariance):
#
from pyrolite.util.plot.axes import share_axes, subaxes
from pyrolite.util.distributions import lognorm_to_norm, norm_to_lognorm

# starting from a normal distribution, then creating similar non-normal distributions
mean, sd = 2.5, 1.5  #
logmu, logs = norm_to_lognorm(mean, sd)  # parameters for equival
normrv = norm(loc=mean, scale=sd)
lognormrv = lognorm(s=logs, scale=logmu)
poissonrv = poisson(mu=mean)
########################################################################################
# We can visualise the similarities and differences between these distributions:
#
fig, ax = plt.subplots(2, 3, figsize=(8, 4))
ax = ax.flat
for a in ax:
    a.subax = subaxes(a, side="bottom")

share_axes(ax[:3], which="x")
share_axes(ax[3:], which="x")
ax[0].set_xlim(-2, 10)
ax[3].set_xscale("log")
ax[3].set_xlim(0.1, 10)

for a in ax:
    a.axvline(0, color="k", lw=0.5, ls="--")

# xs at which to evaluate the pdfs
x = np.linspace(-5, 15.0, 1001)

for ix, dist in enumerate([normrv, lognormrv, poissonrv]):
    _xs = dist.rvs(size=10000)  # random sample
    _ys = -0.05 + np.random.randn(10000) / 100  # random offsets for visualisation
    for a in [ax[ix], ax[ix + 3]]:
        a.annotate(
            "mean={:.2f}, var={:.2f}".format(np.mean(_xs), np.var(_xs)),
            xy=(0.05, 1.05),
            ha="left",
            va="bottom",
            xycoords=a.transAxes,
        )
        a.subax.scatter(_xs, _ys, s=2, color="k", alpha=0.01)
        if dist != poissonrv:  # cont. distribution
            a.plot(x, dist.pdf(x), color="Purple", alpha=0.6, label="pdf")
        else:  # discrete distribution
            a.vlines(
                x[x >= 0],
                0,
                dist.pmf(x[x >= 0]),
                color="Purple",
                alpha=0.6,
                label="pmf",
            )

fig.suptitle("Data Distributions: Normal, Lognormal, Poisson", y=1.1)
plt.tight_layout()
########################################################################################
# Accounting for these inherent features of geochemical data will allow you to
# accurately estimate means and variances, and from this enables the use of
# standardised statistical measures - as long as you're log-transforming your data.
# When performing multivariate analysis, use log-ratio transformations (including the
# additive logratio :func:`~pyrolite.comp.codata.alr`, centred logratio
# :func:`~pyrolite.comp.codata.clr` and isometric logratio
# :func:`~pyrolite.comp.codata.ilr`). In this case, the logratio-mean is implemented for
# you:
#
from pyrolite.comp.codata import logratiomean
import itertools

fig, ax = plt.subplots(2, 2, figsize=(12, 12), subplot_kw=dict(projection="ternary"))
ax = ax.flat

for columns, a in zip(itertools.combinations(["A", "B", "C", "D"], 3), ax):
    columns = list(columns)

    df.loc[:, columns].pyroplot.scatter(
        ax=a, color="k", marker=".", label=df.name, no_ticks=True
    )

    df.mean().loc[columns].pyroplot.scatter(
        ax=a,
        edgecolors="red",
        linewidths=2,
        c="none",
        s=50,
        label="Arithmetic Mean",
        no_ticks=True,
    )

    logratiomean(df.loc[:, columns]).pyroplot.scatter(
        ax=a,
        edgecolors="k",
        linewidths=2,
        c="none",
        s=50,
        label="Geometric Mean",
        axlabels=True,
        no_ticks=True,
    )
    a.legend(frameon=False, facecolor=None, loc=(0.8, 0.5))


import numpy as np

def prob_not(n:int = 20, days:int = 365):

    """
    probability of the birth dates not coinciding
    n : number of students in class
    days : days in the year (default 365)
    formulation:
        d! / ((d**n) * (365 - n)!)

    source : https://en.wikipedia.org/wiki/Birthday_problem

    """

    prob_no = np.math.factorial(days) / ((days**n) * np.math.factorial(days - n))

    return print("Probability of not coinciding: ", "{:.2%}".format(prob_no), "\n", "Probability of coinciding: ", "{:.2%}".format(1 - prob_no), "\n")

prob_not(20, 365)


import numpy as np

def loss(weights, cov, means, q):
    '''
    Loss function for markowitz mean-variance optimization. q \in [0, \infty), represents risk tolerance.
    '''
    term1 = np.matmul( weights.T , np.matmul(cov, weights) )
    term2 = - q*np.matmul( means.T, weights )
    return term1 + term2


import numpy as np
import pandas as pd
import scipy.spatial.distance as dt
import cvxopt as cvx
import matplotlib.pyplot as plt

images = np.genfromtxt("hw06_images.csv", delimiter=",")
labels = np.genfromtxt("hw06_labels.csv", delimiter=",")

# Divide the data, 1000 to training, 4000 to test
X_train = images[:1000]
y_train = labels[:1000].astype(int)
X_test = images[-4000:]
y_test = labels[-4000:].astype(int)
K = 5
# get number of samples and number of features
N_train = len(y_train)
N_test = len(y_test)

# define Gaussian kernel function
def gaussian_kernel(X1, X2, s):
    D = dt.cdist(X1, X2)
    K = np.exp(-D ** 2 / (2 * s ** 2))
    return (K)

def func(y_indexes, X_given, N_given, C, s, epsilon):
    K_trick = gaussian_kernel(X_given, X_given, s)
    yyK = np.matmul(y_indexes[:, None], y_indexes[None, :]) * K_trick
    # print(yyK)
    P = cvx.matrix(yyK)
    q = cvx.matrix(-np.ones((N_given, 1)))
    G = cvx.matrix(np.vstack((-np.eye(N_given), np.eye(N_given))))
    h = cvx.matrix(np.vstack((np.zeros((N_given, 1)), C * np.ones((N_given, 1)))))
    A = cvx.matrix(1.0 * y_indexes[None, :])
    b = cvx.matrix(0.0)

    # use cvxopt library to solve QP problems
    result = cvx.solvers.qp(P, q, G, h, A, b)
    alpha = np.reshape(result["x"], N_given)
    # Most of the alpha values should be 0.
    alpha[alpha < C * epsilon] = 0
    alpha[alpha > C * (1 - epsilon)] = C
    # print(alpha)
    # What is the purpose of cutting small values to 0?
    # What is the purpose of cutting larger values that are close to C directly to C value 10.
    # To find support indices!
    # Non zero alpha coefficient vectors are called support vectors!

    # find bias parameter
    support_indices, = np.where(alpha != 0)
    # print(support_indices)
    active_indices, = np.where(np.logical_and(alpha != 0, alpha < C))
    # Alpha points between 0 and C. As seen in the ipynb subject to.
    w0 = np.mean(
        y_indexes[active_indices] * (
                1 - np.matmul(yyK[np.ix_(active_indices, support_indices)], alpha[support_indices])))
    return alpha, w0

def predict(K_train, K_test, C, s):
    f_predicted_train = []
    f_predicted_test = []
    for k in range(1, K + 1):
        y_indexes = (y_train == k) * 2 - 1
        alpha, w0 = func(y_indexes, X_train, N_train, C, s, epsilon)
        # Train
        f_predicted_train.append(np.matmul(K_train, y_indexes[:, None] * alpha[:, None]) + w0)
        # Test
        f_predicted_test.append(np.matmul(K_test, y_indexes[:, None] * alpha[:, None]) + w0)
    y_predicted_test1 = np.argmax(f_predicted_test, axis=0) + 1
    y_predicted_test1 = y_predicted_test1.reshape(-1)

    y_predicted_train1 = np.argmax(f_predicted_train, axis=0) + 1
    y_predicted_train1 = y_predicted_train1.reshape(-1)

    return y_predicted_train1, y_predicted_test1

C = 10
epsilon = 1e-3
s = 10
K_train = gaussian_kernel(X_train, X_train, s)
K_test = gaussian_kernel(X_test, X_train, s)

y_predicted_train1, y_predicted_test1 = predict(K_train, K_test, C, s)

confusion_matrix = pd.crosstab(y_predicted_train1, y_train, rownames=['y_predicted'], colnames=['y_train'])
print("Confusion_matrix for train:")
print(confusion_matrix)

confusion_matrix = pd.crosstab(y_predicted_test1, y_test, rownames=['y_predicted'], colnames=['y_test'])
print("Confusion_matrix for test:")
print(confusion_matrix)

# Accuracy score
def accuracy_score(y_pred, y_truth):
    score = 0
    for index in range(len(y_truth)):
        if y_pred[index] == y_truth[index]:
            score += 1
    accuracy_score = float(score / len(y_truth))
    return accuracy_score

# Visualization
C_values = [0.1, 1, 10, 100, 1000]
s = 10
train_list = []
test_list = []
for c in C_values:
    # Train
    y_predicted_train, y_predicted_test = predict(K_train, K_test, c, s)

    accuracy_score_train = accuracy_score(y_predicted_train, y_train)
    train_list.append(accuracy_score_train)

    # Test
    accuracy_score_test = accuracy_score(y_predicted_test, y_test)
    test_list.append(accuracy_score_test)

str_list = ["10^-1", "10^0", "10^1", "10^2", "10^3"]
plt.figure(figsize=(10, 6))
plt.plot(str_list, train_list, "-ob", markersize=4, label='training')
plt.plot(str_list, test_list, "-or", markersize=4, label='test')
plt.xlabel("Regularization Parameter (C)")
plt.ylabel("Accuracy")
plt.legend(loc='upper left')
plt.show()


import cfwell.representations as rp
import cfwell.hamiltonian as ht
import cfwell.dynamics as dn

from math import pi, sqrt
from numpy import linspace

M,P = 4,11 # Initial state populations
ket0 = [M,P,0,0] # Initial state representation
natom = M+P # total number of atoms

U,J = 105, 72 # integr. hamiltonian parameters
nu,mu = 0,0 # breaking-of-int. parameters

tm = 2*pi*U/(J*J) * ((M-P)**2 - 1)

t0, tf = 0, 2*tm # initial time / final time
nt = 300 # number of time steps

time = linspace(t0, tf, num=nt)

params = {'interaction': U,
          'hopping': J,
          'break13': nu,
          'break24': mu}

Hint, Htun, Hb13, Hb24, H = ht.make_h(params, natom) # represents the hamilt.

# %% Quantum dynamics

Ni = rp.make_Ni(natom) # represents the Ni operators as matrices

psi0 = rp.representation(ket0) # represents the initial state in a vector

psit = dn.time_evol(psi0, H, time) # time-evolves the init. state
                                   # w/ the hamilt. provided

n1t, n2t, n3t, n4t = dn.quantum_dyn(Ni,            # calculates <n_i(t)> with
                                    time,          # the time-evolved states
                                    psit,          # provided.
                                    natom,
                                    square=False,
                                    plot=True)

n12t, n22t, n32t, n42t = dn.quantum_dyn(Ni,
                                        time,
                                        psit,
                                        natom,
                                        square=True, # enables Ni@Ni, which
                                        plot=True)   # results in:
                                                     # <n_i²(t)>

# %% NOON state fidelity with respect to time

from numpy import array, dot, conj

coefs = 1./2. * array([1, 1, 1, -1]) # superposition coefficients
kets = array([[M,P,0,0], [M,0,0,P], [0,P,M,0], [0,0,M,P]]) # states in superp.

# WARNING: each coefficient is related to each of the "kets" in the same order!

NOON = rp.make_state(coefs, kets)

fids = abs(array([dot(conj(NOON), psit[i,:]) for i in range(len(time))]))

#%% Energy bands

H_struc = [Hint, Htun, Hb13, Hb24] # hamiltonian matrix structures
ujlist, bvals = ht.bands(H_struc,
                         params,
                         natom,
                         plot=True) # energy bands calculation


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

# The rate at which a substance grows is given by

x = symbols( 'x' )
R = 130*exp( 0.4 * x )

a, b = 0, 1.5
growth = integrate( R, ( x, a, b ) )
round( growth, 1 )


# Copyright 2021 BlackRock, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations

from typing import Iterable, Union, cast

import numpy as np

def ackley(x: Union[float, Iterable[float]], a: float = 20, b: float = 0.2, c: float = 2 * np.pi) -> float:
    """https://www.sfu.ca/~ssurjano/ackley.html."""
    if isinstance(x, Iterable):
        x = np.array(x)  # This may consume the iterable (if it's a generator for example)
        n_dimensions = x.size
        if len(x.shape) != 1:
            raise AssertionError("Invalid shape")
    else:
        n_dimensions = 1
    term_1 = a * np.exp(-b * np.sqrt((1 / n_dimensions) * np.sum(x * x)))
    term_2 = np.exp((1 / n_dimensions) * np.sum(np.cos(c * x)))
    res = -term_1 - term_2 + a + np.exp(1)
    return cast(float, res)


import numpy as np
import matplotlib.pyplot as plt
import sys
x=[0.1,0.2,0.3,0.4,0.5,0.6,0.7]
y=[0.2,0.43,0.61,0.756,0.8,0.84,0.95]

x_mean=np.mean(x)
y_mean=np.mean(y)
print(x_mean,y_mean)

least_square=sum((x-x_mean)**2)
numerator=sum((x-x_mean)*(y-y_mean))
print(least_square,numerator)

slope=numerator/least_square
intercept=(y_mean-(slope*x_mean))

plt.scatter(x,y,c='red')
yt=[]
for i in range(0,len(x)):
    yt.append(slope*x[i]+intercept)

r_square=sum((yt-y_mean)**2)/sum((y-y_mean)**2)
std_error=np.sqrt((sum(yt-y_mean)**2)/(len(x)-2))
print(yt)
print('R_Square: ',r_square)
print('Std_Error: ',std_error)
s=0
for i in range(0,len(x)):
    s=s+((y[i]-yt[i])**2)
print('Squared_Error: ',s)
plt.plot(x,yt)
plt.show()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 10 16:15:03 2020

@author: qd
"""
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('seaborn-pastel')

def points_on_circumference(x, y, r, precision=100):
    return [((np.cos(2*np.pi / precision*i))*r + x,
             (np.sin(2*np.pi / precision*i))*r + y)
            for i in np.arange(0, precision+1)]

def current_point_on_circle(xy: tuple, t, r, speed=1,
                            precision=100):
    center_x, center_y = xy[0], xy[1]
    return (np.cos(2*np.pi/precision*(t*speed + center_x))*r,
            np.sin(2*np.pi/precision*(t*speed + center_y))*r)

N_POINTS = 100
RAYON = .5
ANGLE = 0
SPEED = 10
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.axis('equal')
ax.set_xlim([-2, 2])
ax.set_ylim([-2, 2])
scatter = ax.scatter([], [], c='red', marker='+')

points = points_on_circumference(0, 0, RAYON, N_POINTS)

c = plt.Circle((0, 0), RAYON, color='blue', fill=False)
center_circle2 = current_point_on_circle((0, 0), 1, RAYON)
c2 = plt.Circle(center_circle2, RAYON/2, color='blue',
                fill=False)
ax.add_artist(c2)
ax.add_artist(c)
c2_points = points_on_circumference(center_circle2[0],
                                    center_circle2[1],
                                    RAYON/2,
                                    N_POINTS)
pt_x = [x[0] for x in c2_points]
pt_y = [y[1] for y in c2_points]
scatter.set_offsets(np.hstack((pt_x[1*SPEED], pt_y[1*SPEED])))
fig.savefig('test_speed_twocircles_t0.png')


from numpy import std, mean, sqrt
import itertools as it

from bisect import bisect_left
from typing import List

import numpy as np
import pandas as pd
import scipy.stats as ss

from scipy.stats import ranksums

#correct if the population S.D. is expected to be equal for the two groups.
def cohen_d(x,y):
    nx = len(x)
    ny = len(y)
    dof = nx + ny - 2
    return (mean(x) - mean(y)) / sqrt(((nx-1)*std(x, ddof=1) ** 2 + (ny-1)*std(y, ddof=1) ** 2) / dof)

def VD_A(treatment: List[float], control: List[float]):
    """
    Computes Vargha and Delaney A index
    A. Vargha and H. D. Delaney.
    A critique and improvement of the CL common language
    effect size statistics of McGraw and Wong.
    Journal of Educational and Behavioral Statistics, 25(2):101-132, 2000
    The formula to compute A has been transformed to minimize accuracy errors
    See: http://mtorchiano.wordpress.com/2014/05/19/effect-size-of-r-precision/
    :param treatment: a numeric list
    :param control: another numeric list
    :returns the value estimate and the magnitude
    """
    m = len(treatment)
    n = len(control)

    if m != n:
        raise ValueError("Data d and f must have the same length")

    r = ss.rankdata(treatment + control)
    r1 = sum(r[0:m])

    # Compute the measure
    # A = (r1/m - (m+1)/2)/n # formula (14) in Vargha and Delaney, 2000
    A = (2 * r1 - m * (m + 1)) / (2 * n * m)  # equivalent formula to avoid accuracy errors

    levels = [0.147, 0.33, 0.474]  # effect sizes from Hess and Kromrey, 2004
    magnitude = ["negligible", "small", "medium", "large"]
    scaled_A = (A - 0.5) * 2

    magnitude = magnitude[bisect_left(levels, abs(scaled_A))]
    estimate = A

    return estimate, magnitude

if __name__ == '__main__':
    # town03 3.75
    x3 = [156,138,148,167,154,173]
    y3 = [111,110,96,123,107,125]
    # town05 3.67
    x5 = [555,557,546,559,551,549]
    y5 = [517,506,479,523,521,506]
    # town01 10.52
    x1 = [669,675,673,676,679,681]
    y1 = [555,546,511,527,542,510]
    # town07 7.08
    x7 = [409,390,386,368,424,391]
    y7 = [286,281,284,293,292,263]
    # borregas
    xb = [68, 79, 65, 74, 86, 85]
    yb = [49, 44, 51, 47, 65, 48]

    x = xb
    y = yb
    print(x, y)
    print ("cohen d = ", cohen_d(x, y))
    print('Wilcoxon rank-sum statistics p value', ranksums(x, y))
    print('Vargha-Delaney effect size', VD_A(x, y))

import numpy,from numpy,import scipy,from scipy


"""

"""
from numpy.linalg import pinv
from pandas import DataFrame, Series

def normal_equation(
    features: DataFrame, labels: Series, add_theta_zero: bool = False
) -> Series:
    if add_theta_zero:
        features.insert(0, "x0", [1 for _ in range(features.shape[0])])
    return Series(
        pinv(features.transpose().dot(features)).dot(features.transpose()).dot(labels)
    )


import unittest
import numpy as np

class PerceptronTest(unittest.TestCase):
    def AND(self, x1, x2):
        w1, w2, theta = .5, .5, .7
        tmp = x1 * w1 + x2 * w2
        if tmp <= theta:
            return 0
        elif tmp > theta:
            return 1

    def AND2(self, x1, x2):
        x = np.array([x1, x2])
        w = np.array([.5, .5])
        b = -.7
        tmp = np.sum(x * w) + b
        if tmp <= 0:
            return 0
        elif tmp > 0:
            return 1

    def OR(self, x1, x2):
        x = np.array([x1, x2])
        w = np.array([.5, .5])
        b = -.1
        tmp = np.sum(x * w) + b
        if tmp <= 0:
            return 0
        elif tmp > 0:
            return 1

    def NAND(self, x1, x2):
        x = np.array([x1, x2])
        w = np.array([-.5, -.5])
        b = .7
        tmp = np.sum(x * w) + b
        if tmp <= 0:
            return 0
        elif tmp > 0:
            return 1

    def XOR(self, x1, x2):
        s1 = self.OR(x1, x2)
        s2 = self.NAND(x1, x2)
        return self.AND(s1, s2)

    def test_gate(self):
        self.assertEqual(0, self.AND(0, 0))
        self.assertEqual(0, self.AND(0, 1))
        self.assertEqual(0, self.AND(1, 0))
        self.assertEqual(1, self.AND(1, 1))

        self.assertEqual(0, self.AND2(0, 0))
        self.assertEqual(0, self.AND2(0, 1))
        self.assertEqual(0, self.AND2(1, 0))
        self.assertEqual(1, self.AND2(1, 1))

        self.assertEqual(0, self.OR(0, 0))
        self.assertEqual(1, self.OR(0, 1))
        self.assertEqual(1, self.OR(1, 0))
        self.assertEqual(1, self.OR(1, 1))

        self.assertEqual(1, self.NAND(0, 0))
        self.assertEqual(1, self.NAND(0, 1))
        self.assertEqual(1, self.NAND(1, 0))
        self.assertEqual(0, self.NAND(1, 1))

        self.assertEqual(0, self.XOR(0, 0))
        self.assertEqual(1, self.XOR(0, 1))
        self.assertEqual(1, self.XOR(1, 0))
        self.assertEqual(0, self.XOR(1, 1))

    def test_wb(self):
        x = np.array([0, 1])
        w = np.array([.5, .5])
        b = -.7
        print(w * x)
        print(np.sum(w * x))
        print(np.sum(w * x) + b)


import numpy as np

def symmetric_gauss(A):
    if(A.size == 1):
        return np.array([1]), A.copy()

    U = np.eye(A.shape[0])
    U[0, 1:] = -A[0, 1:]/A[0,0]
    U_next = np.eye(A.shape[0])
    A_new = np.matmul(U.T, np.matmul(A, U))
    U_next[1:, 1:], A_new[1:, 1:] = symmetric_gauss(A_new[1:, 1:])
    return np.matmul(U, U_next), A_new.diagonal()

def cholesky(A):
    U, D = symmetric_gauss(A)
    E = np.diag(np.sqrt(D))
    return solve_triangular(U.T, E, lower=True).T

def factor_QR(A):
    if A.size == 1:                     #Base case
        return A/np.linalg.norm(A), np.linalg.norm(A)

    if A.size == 0:
        return np.eye(A.shape[0]), A

    x_bar = np.zeros((A.shape[0]))
    x_bar[0] = np.linalg.norm(A[:,0])

    u = A[:,0]-x_bar

    u = u/np.linalg.norm(u)

    mirror = (np.eye(A.shape[0])-2*np.outer(u, u))

    B = np.matmul(mirror, A)

    Q_next = np.eye((A.shape[0]))
    Q_next[1:, 1:], B[1:, 1:] = factor_QR(B[1:, 1:])

    return np.matmul(mirror.T, Q_next), B

def rotation_QR(A):
    if A.size == 1:                     #Base case
        return A/np.linalg.norm(A), np.linalg.norm(A)

    if A.size == 0:
        return np.eye(A.shape[0]), A

    B = A.copy()

    Q = np.eye(B.shape[0])

    for i in range(1, B.shape[0]):
        if B[i, 0]!=0:
            r = np.sqrt(B[0, 0]**2 + B[i, 0]**2)
            cosine_phi = B[0, 0]/r
            sine_phi = B[i,0]/r

            rot = np.eye(B.shape[0])        #Build the rotation matrix
            rot[0, 0] = cosine_phi
            rot[i, 0] = -sine_phi
            rot[0, i] = sine_phi
            rot[i, i] = cosine_phi

            B = np.matmul(rot, B)
            Q = np.matmul(Q, rot.T)

    Q_next = np.eye(B.shape[0])
    Q_next[1:, 1:], B[1:, 1:] = rotation_QR(B[1:, 1:])    #Recurse

    return np.matmul(Q, Q_next), B

def gram_schmidt(A):
    Q = np.zeros((A.shape[0], A.shape[0]), np.complex_)
    R = np.zeros_like(A, np.complex_)
    Q[:,0] = A[:, 0]
    norm = np.linalg.norm(Q[:, 0])
    Q[:, 0] = Q[:, 0]/norm
    R[0,0] = norm

    for i in range(1, A.shape[1]):
        coefficients = np.zeros((i), np.complex_)
        for k in range(i):
            coefficients[k] = np.dot(np.conj(A[:, i]), Q[:, k])

        Q[:, i] = A[:, i]-np.matmul(Q[:, :i], coefficients)
        norm = np.linalg.norm(Q[:, i])
        Q[:, i] = Q[:, i]/norm
        R[:i, i] = coefficients
        R[i,i] = norm

    return Q, R

def modified_gram_schmidt(A):
    R = np.zeros_like(A, np.complex_)
    Q = np.zeros((A.shape[0], A.shape[0]), np.complex_)

    V = A.astype(np.complex_)

    for i in range(A.shape[1]):
        R[i,i] = np.linalg.norm(V[:, i])
        q = V[:, i]/R[i,i]
        Q[:, i] = q
        for k in range(i, A.shape[1]):
            R[i, k] = np.dot(np.conj(q), V[:, k])
            V[:, k] = V[:, k]-R[i,k]*q

    return Q, R

if __name__=="__main__":
    Q, R = rotation_QR(np.array([[1.0,2.0, -4, 1], [3.0, 4.0,234.4, -3], [2,1,2,0.0004], [0,0,2,0]]))
    #Q, R = factor_QR(np.array([[1, -2], [1, 0], [1, 1], [1, 3]]).T)
    print(np.matmul(Q, Q.T))
    print()
    print(R)
    print()
    print(np.matmul(Q, R))


import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import random

normal_array = np.random.normal(79, 15, 80)

sns.set()
plt.hist(normal_array, color='grey', bins=50)

four_by_four_matrix = np.matrix(np.ones((4,4), dtype=float))

np.asarray(four_by_four_matrix)[2] = 2 # 3 row mude pra 2

whole_numbers = np.arange(2, 20, 2)

np.linspace(1.0, 5.0, num=10)

np.linspace(1.0, 5.0, num=5, endpoint=False)

natural_numbers = np.arange(1, 20, 1)

odd_numbers = np.arange(1, 20, 2)

even_numbers = np.arange(2, 20, 2)

np.logspace(2, 4.0, num=4)

x = np.array([1,2,3], dtype=np.complex128)
# print(x.itemsize)

np_list = np.array(([1,2,3], [4,5,6]))
print(np_list[0])
print(np_list[1])
print(np_list[:,0])
print(np_list[:,1])
print(np_list[:,2])


#coding=utf-8
import scipy.stats as stats
import numpy as np

def confidenceInterval(n_respondents, n_total, n_LikertLevels=3, significanceLevel=0.05, debug=False):
    """
    Description:
    --------------------
    This calculates the confidence interval for a Likert Response with k Likert scale levels.

    It uses the equation:

    Response% +/- ConfidenceInterval =

    (n_i + B/2) / (n + B) +/- sqrt( (B**2/4 + B * n_i * (1 - n_i/n)) / (n + B)**2 )

    where:

    n_i = number of respondents choosing the i-th level

    n = SUM(n_i, from:i=1, to:k), i.e. the total number of responses to the question

    k = maximum Likert scale levels (in our case, 3 after data is condensed)

    B = upper (alpha / k) 100th percentile of the chisquare distribution
        with 1 degree of freedom. (in this case 95%)

    EXAMPLE:
    --------
    Sample Question: "When doing a physics experiment, I don't think much
    about sources of systematic error. What do YOU think?"

    Data:
    -----
    Strongly Agree    : 95
    Agree             : 218
    Neutral           : 196
    Disagree          : 86
    Strongly Disagree : 27
    N/A               : 11

    for 6 scale likert scale (Strongly Agree to Strongly Disagree + N/A)
    95% Confidence Interval, alpha=0.05, k=6:

    Using R:
    > qchisq(0.05/6,1, lower.tail=FALSE)
    [1] 6.960401

    NOTE, in R:

    lower.tail logical; if TRUE (default), probabilities are P[X ≤ x],
    otherwise, P[X > x].

    But since this is Python:

    In [1]: import scipy.stats as stats

    In [2]: stats.chi2.ppf(1-0.05/6,1)
    Out[2]: 6.96040144105298

    NOTE, in Python:

    There is no 'lower.tail' to switch the range of the probability, thus
    we do '1-0.05/6'. (remember that 6 is just the number of Likert options
    in this example).

    Confidence Interval for percent saying "Strongly Agree":

    StronglyAgree% +/- CI = (95 + 6.96/2) / (633 + 6.96) +/- sqrt( (6.96**2/4 + 6.96 * 95 * (1 - 95/633)) / (633 + 6.96)**2 )
    StronglyAgree% +/- CI = 0.154 +/- 0.037

    Sources:
    [1] slide 13-14, http://faculty.nps.edu/rdfricke/OA4109/Lecture%209-1%20--%20Introduction%20to%20Survey%20Analysis.pdf
    [2] Accepted response, http://stackoverflow.com/questions/18070299/is-there-a-python-equivalent-of-rs-qchisq-function
    [3] scipy documentation, http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chi2.html
    [4] R documentation, https://stat.ethz.ch/R-manual/R-patched/library/stats/html/Chisquare.html

    Parameters:
    -------------------
    n_respondents : int (n_i)
    number of respondents with likert scale

    n_LikertLevels : int (k) : Default=3
    number of Likert Levels. Default is 3 due to combination of Likert
    responses (Strongly Dis/Agree and Dis/Agree)

    n_total : int (n)
    number of total responses to question

    significanceLevel : float (alpha = B * k) : Default=0.05
    The significance level typically known as 'alpha'. Default is 0.05.

    debug: Boolean : Default=False
    If True, returns B value.

    Returns:
    -------------------
    B : float : Default does not return
    The value returned from scipy.stats.chi2.ppf

    ResponsePercent : float
    Value responding with selected response.

    ConfidenceInterval : float
    The upper and lower bound of the interval.
    """
    if isinstance(n_respondents, int)==False:
        raise ValueError('n_respondents needs to be an integer.')

    if isinstance(n_LikertLevels, int)==False:
        raise ValueError('n_LikertLevels needs to be an integer.')

    if isinstance(n_total, int)==False:
        raise ValueError('n_total needs to be an integer.')

    if isinstance(significanceLevel, float)==False:
        raise ValueError('significanceLevel needs to be a float.')

    if significanceLevel > 1 or significanceLevel < 0:
        raise ValueError('significanceLevel needs to be between 0 and 1.')

    if n_respondents <= 0:
        raise ValueError('n_respondents needs to be greater than 0.')

    if n_LikertLevels <= 0:
        raise ValueError('n_LikertLevels needs to be greater than 0.')

    if n_total <= 0:
        raise ValueError('n_total needs to be greater than 0.')

    B = stats.chi2.ppf(1-significanceLevel/n_LikertLevels, 1)

    ResponsePercent = (n_respondents + B/2) / (n_total + B)
    ConfidenceInterval = np.sqrt(((B**2)/4 + B * n_respondents * (1 - n_respondents/n_total))/(n_total + B)**2)

    if debug==True:
        return B, ResponsePercent, ConfidenceInterval
    else:
        return ResponsePercent, ConfidenceInterval


import numpy as np
import pandas as pd
import csv
from sklearn.datasets.base import Bunch
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import ShuffleSplit
from sklearn.metrics import r2_score
from collections import defaultdict

X = [[0, 15], [1, -10]]
print(StandardScaler().fit(X).transform(X))

iris_data_set = datasets.load_iris()
x = iris_data_set.data
y = iris_data_set.target
print(iris_data_set['feature_names'])
# print(x, y)

def load_my_fancy_dataset():
    with open('ds1.csv') as csv_file:
        data_file = csv.reader(csv_file)
        temp = next(data_file)
        n_samples = int(temp[0])
        n_features = int(temp[1])
        data = np.empty((n_samples, n_features))
        target = np.empty((n_samples,), dtype=np.int)
        feature_names = temp[2:]

        for i, sample in enumerate(data_file):
            data[i] = np.asarray(sample[:-1], dtype=np.float64)
            target[i] = np.asarray(sample[-1], dtype=np.int)

    return Bunch(data=data, target=target, feature_names=feature_names)

def mean_decrease_impurity():
    boston = datasets.load_boston()
    X1 = boston["data"]
    print(type(X1), X1.shape)
    Y1 = boston["target"]
    names = boston["feature_names"]
    print(names)
    rf = RandomForestRegressor()
    rf.fit(X1, Y1)
    print("Features sorted by their score:")
    print(sorted(zip(map(lambda a: round(a, 4), rf.feature_importances_), names), reverse=True))

def mean_decrease_accuracy():
    boston = datasets.load_boston()
    X1 = boston["data"]
    Y1 = boston["target"]
    names = boston["feature_names"]
    rf = RandomForestRegressor()
    scores = defaultdict(list)
    shuff_split = ShuffleSplit(5, test_size=0.3, random_state=100)
    for train_idx, test_idx in shuff_split.split(X1):
        X_train, X_test = X1[train_idx], X1[test_idx]
        Y_train, Y_test = Y1[train_idx], Y1[test_idx]
        r = rf.fit(X_train, Y_train)
        acc = r2_score(Y_test, rf.predict(X_test))
        for i in range(X1.shape[1]):
            print("shuff:%d" % i)
            X_t = X_test.copy()
            np.random.shuffle(X_t[:, i])
            shuff_acc = r2_score(Y_test, rf.predict(X_t))
            scores[names[i]].append((acc - shuff_acc) / acc)

    print("Features sorted by their score:")
    print(sorted([(round(np.mean(score), 4), feat) for feat, score in scores.items()], reverse=True))

def pandas_demo():
    pd_data = pd.read_csv("ds2.csv")
    X1 = pd_data[["first_feat", "second_feat", "third_feat"]]
    Y1 = pd_data["flag"]
    rf = RandomForestRegressor()
    rf.fit(X1, Y1)
    print("特征重要性：", rf.feature_importances_)

if __name__ == '__main__':
    # data1 = load_my_fancy_dataset()
    # print(data1['feature_names'])
    # print(data)
    # mean_decrease_impurity()
    # mean_decrease_accuracy()
    pandas_demo()


import numpy as np

def Lanczos(t0,t,fc,ftype='high'):
	'''
	Calculate the Lanczos-squared function centred upon t0 for an
	arbitrary set of points in time.

	'''

	#find the points within 1.5*(1.0/fc) of t0 to apply the function
	#the rest will be set to zero
	n = t.size
	filt = np.zeros(n,dtype='float32')
	pc = 1.0/fc
	use = np.where((t > t0-1.5*pc) & (t < t0+1.5*pc))[0]

	#get dt
	dt = (t[use] - t0)/(1.5*pc)

	#calculate the function
	pidt2 = np.pi*dt
	filt[use] = (np.sin(pidt2)/pidt2)**2
	filt[use] = filt[use]*np.sin(pidt2*3)/(pidt2*3)

	#check if any of the dt's are 0
	dt0 = np.where(pidt2 == 0)[0]
	if dt0.size > 0:
		filt[use[dt0]] = 1.0

	#calculate the normalization factor (integrate)
	#tr = t[use[-1]] - t[use[0]]
	norm = np.trapz(filt[use])
	#norm = np.trapz(filt[use],(use.size-1)*(t[use]-t[use[0]])/tr)
	if ftype == 'low':
		filt = filt/norm
	else:
		ic = np.where(t == t0)[0]
		filt = -filt/norm
		filt[ic] = 1.0

	return filt


# project euler https://projecteuler.net/

# 1. Find the sum of all positive integers less than 1000 that are multiples of 3 or 5
def sum_mulitples(x, y, n):
    """find the sum of all multiples of x and y less than n"""
    return sum([(num % x == 0 or num % y == 0)*num for num in range(1, n)])

print('sum_mulitples', sum_mulitples(3, 5, 1000))

# 2. Find the sum of the even-valued terms in the Fibonacci sequence whose values do not exceed four million.
def sum_even_fibonacci(n):
    """sum of the even-valued terms of the fibonacci sequence not exceeding n"""
    result = 0
    if n >= 2:
        x, y = 1, 1
        for _ in range(n):
            x, y = y, x + y
            if x > n:
                break
            if x % 2 == 0:
                # print(x, y)
                result += x
    return result

print('sum_even_fibonacci', sum_even_fibonacci(4000000))

# 3. What is the largest prime factor of the number 600851475143?
def largest_prime_factor(n):
    """find the largest prime factor of n"""
    # NOTE 600851475143 is way too big to find every possible factor quickly.
    # we must divide n by every "prime" starting from 2.
    current = 2
    max_factor = n
    while current < max_factor:
        while max_factor % current == 0:
            max_factor = max_factor//current
            # print(current, max_factor)
        if current % 2 == 0:
            current += 1
        else:
            current += 2
    return max_factor

print('largest_prime_factor', largest_prime_factor(600851475143))

# 4. What is the largest palindromic number that is the product of two 3 digit numbers?
def largest_palindrome_number(lo, hi):
    """largest palindromic product within a given range (using strings)"""
    result = 0
    for i in reversed(range(lo, hi)):
        for j in reversed(range(lo, hi)):
            val = list(str(i*j))
            # print(i, j, val)
            is_palindrome = True
            for k in range(len(val)//2 + 1):
                # print(i, j, k, val, val[k], val[len(val)-1-k])
                if val[k] != val[len(val)-1-k]:
                    is_palindrome = False
                    break
            if is_palindrome:
                # print(i, j, val)
                if i*j > result:
                    result = i*j
    return result
# 111**2 = 12321

print('largest_palindrome_number', largest_palindrome_number(100, 1000))

# 5. What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
def find_sequence_scm(n: int) -> int:
    """finds the smallest number that divides everything from 1 to n"""
    factorial = 1
    for i in range(2, n+1):
        factorial *= i
    # this number is a multiple of the LCM.
    for i in range(n, factorial, n):
        if (factorial % i == 0):
            for factor in range(2, n+1):
                if i % factor != 0:
                    break  # not the scm
                if factor == n:
                    return i
    return factorial  # default

print('find_sequence_scm', find_sequence_scm(20))

# 6. Find the difference between the sum of the squares and the square of the sum of the first 100 natural numbers.
def diff_sum_squares(n: int) -> int:
    """difference between the sum of the squares and the square of the sum of the first n naturals"""
    return sum([i for i in range(1, n+1)])**2 - sum([i**2 for i in range(1, n+1)])

print('diff_sum_squares', diff_sum_squares(100))

# 7. What is the 10001st prime number?
def find_nth_prime(n: int) -> int:
    """modified sieve checks every natural number against all previous primes to find the nth prime"""
    assert n >= 2
    current = 3
    primes = [current]
    if n == 1:
        return current
    # add 1 continuously in a loop checking if the number divides any of the previously found primes
    while len(primes) < n:
        if current == 2:
            current += 1
        else:
            current += 2
        is_prime = True
        for prime in primes:
            if current % prime == 0:
                is_prime = False
                break  # not a prime
        if is_prime:
            primes.append(current)
            # print(primes)
    return primes[-1]

print('find_nth_prime', find_nth_prime(10001))

# 8. Find thirteen adjacent digits in the 1000-digit number that have the greatest product
def greatest_sequence_product(val: int, n: int) -> (int, list):
    """given an integer find the subsequence of a given length having the greatest product"""
    digits = list(map(int, str(val)))
    max_product = 0
    for index in range(len(digits)):
        sequence = digits[index:index+n]
        if len(sequence) < n:
            break
        product = digits[index]
        for s in sequence[1:n]:
            product *= s
        if max_product < product:
            max_product = product
        # print(index, sequence, product, max_product)
    return max_product, sequence

# val = 1234567890
val = 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
print('greatest_sequence_product', greatest_sequence_product(val, 13))  # 13

# 9. Find the Pythagorean triplet for which a + b + c = 1000 and return its product.
def pythagorean_triplet(n: int) -> ((int, int, int), int):
    """find the Pythagorean triplet whose sum equal n and return its product. """
    import math
    for c in reversed(range(int(math.sqrt(n)), n//2)):
        for b in reversed(range(1, c)):
            a = n - c - b
            if a > c:
                break
            # print("c", c, "b", b, "a", a)
            if (c**2 == a**2 + b**2):
                return (a, b, c), a*b*c

# [((200, 375, 425), 31875000)]
print('pythagorean_triplet', pythagorean_triplet(1000))

# 10. Find the sum of the primes less than two million.

def sum_of_primes(n: int) -> int:
    """return the sum of all primes less than n"""
    # just find every prime using erastosthenes, and tally as you find them
    return sum(find_primes(n))

def find_primes(max_value):
    """returns every prime up to a given value."""

    # todo use tuple instead of dict, almost as fast
    numbers = {a: True for a in range(2, max_value+1)}
    sieve = [n for n in numbers if n <= max_value**0.5]
    for current in sieve:
        if numbers[current]:
            prime_multiple = current**2
            while prime_multiple <= max_value:
                if numbers[prime_multiple]:
                    numbers[prime_multiple] = False
                prime_multiple += current
    primes = [p for p in numbers if numbers[p]]
    return primes

print('sum_of_primes', sum_of_primes(2000000))

# 11. Find the maximum product of four adjacent numbers in a 20x20 matrix.

def matrix_search(my_list: list) -> int:
    import numpy as np
    arr = np.array(my_list)
    (x, y) = arr.shape
    # print(arr)
    return crawl_matrix(arr, x)

def crawl_matrix(arr, n):
    import numpy as np
    max_product = 0
    for x in range(n):
        for y in range(n):
            perform_vertical_check = False
            if (x+3 <= n-1):
                perform_vertical_check = True
                max_product = check_vertical(arr, x, y, max_product)
                if (y-3 >= 0):
                    max_product = check_backward_diag(arr, x, y, max_product)
            if (y+3 <= n-1):
                max_product = check_horizontal(arr, x, y, max_product)
                if (perform_vertical_check):
                    max_product = check_forward_diag(arr, x, y, max_product)
    return max_product

def check_vertical(arr, x, y, max_product):
    product = arr[x,y]
    for i in range(x+1, x+4):
        product *= arr[i, y]
        if (product > max_product):
            max_product = product
            # print("vertical", x, y, arr[x,y], "max_product", max_product)
    return max_product

def check_backward_diag(arr, x, y, max_product):
    product = arr[x, y]
    j = y
    for i in range(x+1, x+4):
        j -= 1
        product *= arr[i, j]
        if (product > max_product):
            max_product = product
            # print("back diag", x, y, arr[x,y], "max_product", max_product)
    return max_product

def check_horizontal(arr, x, y, max_product):
    product = arr[x, y]
    for j in range(y+1, y+4):
        product *= arr[x, j]
        if (product > max_product):
            max_product = product
            # print("horizontal", x, y, arr[x,y], "max_product", max_product)
    return max_product

def check_forward_diag(arr, x, y, max_product):
    product = arr[x, y]
    j = y
    for i in range(x+1, x+4):
        j += 1
        product *= arr[i, j]
        if (product > max_product):
            max_product = product
            # print("fwd diag", x, y, arr[x,y], "max_product", max_product)
    return max_product

my_matrix = [
    [8,  2, 22, 97, 38, 15,  0, 40,  0, 75,  4,  5,  7, 78, 52, 12, 50, 77, 91,  8],
    [49, 49, 99, 40, 17, 81, 18, 57, 60, 87, 17, 40, 98, 43, 69, 48,  4, 56, 62,  0],
    [81, 49, 31, 73, 55, 79, 14, 29, 93, 71, 40, 67, 53, 88, 30,  3, 49, 13, 36, 65],
    [52, 70, 95, 23,  4, 60, 11, 42, 69, 24, 68, 56,  1, 32, 56, 71, 37,  2, 36, 91],
    [22, 31, 16, 71, 51, 67, 63, 89, 41, 92, 36, 54, 22, 40, 40, 28, 66, 33, 13, 80],
    [24, 47, 32, 60, 99,  3, 45,  2, 44, 75, 33, 53, 78, 36, 84, 20, 35, 17, 12, 50],
    [32, 98, 81, 28, 64, 23, 67, 10, 26, 38, 40, 67, 59, 54, 70, 66, 18, 38, 64, 70],
    [67, 26, 20, 68,  2, 62, 12, 20, 95, 63, 94, 39, 63,  8, 40, 91, 66, 49, 94, 21],
    [24, 55, 58,  5, 66, 73, 99, 26, 97, 17, 78, 78, 96, 83, 14, 88, 34, 89, 63, 72],
    [21, 36, 23,  9, 75,  0, 76, 44, 20, 45, 35, 14,  0, 61, 33, 97, 34, 31, 33, 95],
    [78, 17, 53, 28, 22, 75, 31, 67, 15, 94,  3, 80,  4, 62, 16, 14,  9, 53, 56, 92],
    [16, 39,  5, 42, 96, 35, 31, 47, 55, 58, 88, 24,  0, 17, 54, 24, 36, 29, 85, 57],
    [86, 56,  0, 48, 35, 71, 89,  7,  5, 44, 44, 37, 44, 60, 21, 58, 51, 54, 17, 58],
    [19, 80, 81, 68,  5, 94, 47, 69, 28, 73, 92, 13, 86, 52, 17, 77,  4, 89, 55, 40],
    [4,  52,  8, 83, 97, 35, 99, 16,  7, 97, 57, 32, 16, 26, 26, 79, 33, 27, 98, 66],
    [88, 36, 68, 87, 57, 62, 20, 72,  3, 46, 33, 67, 46, 55, 12, 32, 63, 93, 53, 69],
    [4,  42, 16, 73, 38, 25, 39, 11, 24, 94, 72, 18,  8, 46, 29, 32, 40, 62, 76, 36],
    [20, 69, 36, 41, 72, 30, 23, 88, 34, 62, 99, 69, 82, 67, 59, 85, 74,  4, 36, 16],
    [20, 73, 35, 29, 78, 31, 90,  1, 74, 31, 49, 71, 48, 86, 81, 16, 23, 57,  5, 54],
    [1,  70, 54, 71, 83, 51, 54, 69, 16, 92, 33, 48, 61, 43, 52,  1, 89, 19, 67, 48]
]

print("matrix max product", matrix_search(my_matrix))

# 12 What is the value of the first triangle number to have over five hundred divisors?
def triangle_number_divisors(n) -> int:
    '''
    returns the first triangle number with at least n divisors
    '''
    # outer loop adds up the natural numbers and keeps sum
    t = 0  # the natural numbers
    s = t  # the sum of t
    d = 0  # the count of divisors of s
    while n >= d:
        t += 1
        s += t
        # inner loop finds divisors of each and breaks when it finds one with > n divisors
        d = 0
        for i in range(1, s//2):
            if i > s//i:
                break
            if s % i == 0:
                d += 2
    return(s)

print("triangle_number_divisors ", triangle_number_divisors(500))


import numpy as np
import pandas
from ggplot import *

def normalize_features(array):
    """Normalized the features in the data set"""
    array_normalized = (array-array.mean())/array.std()
    mu = array.mean()
    sigma = array.std()

    return array_normalized, mu, sigma

def compute_cost(features, values, theta):
    """
    Compute the cost function fiven a set of features/values,
    and the values for our thetas
    """
    m = len(values)
    H = np.dot(features, theta)
    cost = (np.square(H-values)).sum().(2*m)

    return cost

def gradient_descent(features,values,theta, alpha, num_iterations)
    """
    Perform gradient descent given a data set with an arbitrary number of features
    """
    m = len(values)
    cost_history = []

    for i in range(num_iterations):
        J = compute_cost(features, values, theta)
        cost_history.append(J)
        H = np.dot(features, theta)
        GD = (alpha/m)*np.dot((values-H), features)
        theta = np.add(theta,GD)

    return theta, pandas.Series(cost_history)

def plot_cost_history(alpha, cost_history):
    """
    Viewing plot for our cost history

    For function called only in the function it self, print this return function

    """
    cost_df = pandas.DataFrame({
        'Cost_History': cost_history,
        'Iteration': range(len(cost_history))
})
    return ggplot(cost_df, aes('Iteration', 'Cost_History')) + \
            geom_point() + ggtitle('Cost History for alpha = %.3f' % alpha )

def predictions(features,values,alpha,num_iterations):

    m = len(values)

    features,mu,sigma = normalize_features(features)

    #create one features with one. This acts like constanta, bias unit.
    features['ones'] = np.ones(m)

    #If we look here, features and values is turned into np object array
    #So we can do vectorize computation, without even to use (np.add, np.subtract, etc)
    features_array = np.array(features)
    values_array = np.array(values).flatten()#return a copy of the array collapsed into one dimension

    #Init theta, perform gradient descent
    theta_gradient_descent = np.zeros(len(features.columns))
    theta_gradient_descent, cost_history = gradient_descent(features_array,
                                                            values_array,
                                                            theta_gradient_descent,
                                                            alpha,
                                                            num_iterations
                                                            )

    plot = None
    #Uncomment to see
    #plot = plot_cost_history(alpha, cost_history)
    predictions = np.dot(features_array, theta_gradient_descent)
    return predictions, plot

def separate_data_from_predictions(dataframe):
        """
    dataframe itself is a pandas dataframe called weather_turnstile in the Udacity Class
    We use the predictions function to predict ridership NYC subway using linear regresion with gradient descent

    Separate the input from predictions to encapsulate it
    """

    dummy_units = pandas.get_dummies(dataframe['UNIT'], prefix='unit')
    features = dataframe[['rain','precipi', 'Hour', 'meantempi']].join(dummy_units)
    values = dataframe[['ENTRIESn_hourly']]

    #Set MANUAL alpha, num_iter
    alpha = 0.1
    num_iterations = 75

    return predictions(features,values,alpha,num_iterations)


import pandas as pd
import numpy as np
import math
import sys
import os
def get_weight(a):
    w=a.split(',')
    for i in range(len(w)):
        if w[i]=="'1" or w[i]=="1'":
            w[i]='1'
    weights=[]
    for j in range(len(w)):
        weights.append(int(w[j]))
    return weights
def get_impact(a):
    impact=a.split(',')
    for i in range(len(impact)):
        if impact[i]=="'+" or impact[i]=="+'":
            impact[i]='+'
        if impact[i]=="'-" or impact[i]=="-'":
            impact[i]='-'
    return impact
def num_col(df,n_cols):
    num=[]
    for i in range(n_cols):
        if df.iloc[:,i:i+1].dtypes[0]=='float64':
            num.append(df.iloc[:,i:i+1].columns[0])
    return num
def non_num_col(df,num):
    non_num=[]
    for i in df.columns:
        if i not in num:
            non_num.append(i)
    return non_num
def weight_normalised(df,num,weights):
    sqrt_column_sum=[]
    for i in df.columns:
        if i in num:
            sqrt_column_sum.append(round(math.sqrt(df[i].pow(2).sum(axis=0)),2))
    j=0
    for i in df.columns:
        if i in num:
            df[i]=round(df[i].div(sqrt_column_sum[j]),2)
            j=j+1
    j=0
    for i in df.columns:
        if i in num:
            df[i]=round((df[i]*weights[j]),2)
            j=j+1
    return df
def V_positive(df,num,impact):
    V_pos=[]
    j=0
    for i in num:
        if impact[j]=='+':
            V_pos.append(df[i].max())
        else:
            V_pos.append(df[i].min())
        j=j+1
    return V_pos
def V_negative(df,num,impact):
    V_neg=[]
    j=0
    for i in num:
        if impact[j]=='+':
            V_neg.append(df[i].min())
        else:
            V_neg.append(df[i].max())
        j=j+1
    return V_neg
def S_positive(arr,r,c,V_pos):
    S_pos=[]
    s=0
    for i in range(r):
        for j in range(c):
            s=s+(arr[i][j]-V_pos[j])**(2)
        S_pos.append(round(math.sqrt(s),2))
        s=0
    return S_pos
def S_negative(arr,r,c,V_neg):
    S_neg=[]
    s=0
    for i in range(r):
        for j in range(c):
            s=s+(arr[i][j]-V_neg[j])**(2)
        S_neg.append(round(math.sqrt(s),2))
        s=0
    return S_neg
def performance(r,S_pos,S_neg):
    per=[]
    for i in range(r):
        per.append(round(S_neg[i]/(S_neg[i]+S_pos[i]),2))
    return per
def main():
    print(sys.argv)
    if len(sys.argv)!=5:
        print("Error!! wrong number of parameters")
        print("Pass four parameters")
        print("example python ass6.py data.csv '1,1,1,1' '+,+,-,+' out.csv")
        exit(0)
    try:
        df=pd.read_csv(sys.argv[1])
        n_cols=len(df.columns)
        if n_cols<=2:
            print("Error!")
            print("pass at least three rows")
            sys.exit(0)
        weights=get_weight(sys.argv[2])
        impact=get_impact(sys.argv[3])
        for i in range(len(impact)):
            if impact[i]!="+" and impact[i]!="-":
                print("Error!")
                print("Impact is either + or -")
                sys.exit(0)
        num=num_col(df, n_cols)
        if len(weights)!=len(num) and len(impact)!=len(num):
            print("Error!")
            print("Pass correct number of weights and impact")
            sys.exit(0)
        non_num=non_num_col(df, num)
        df=weight_normalised(df, num,weights)
        V_pos=V_positive(df, num,impact)
        V_neg=V_negative(df, num,impact)
        fd=df.drop(non_num,axis=1)
        arr=fd.to_numpy()
        r=len(arr)
        c=len(arr[0])
        S_pos=S_positive(arr, r, c, V_pos)
        S_neg=S_negative(arr, r, c, V_neg)
        per=performance(r, S_pos, S_neg)
        fd['TOPSIS SCORE']=per
        fd['Rank'] = fd['TOPSIS SCORE'].rank(ascending=0)
        if os.path.isfile(sys.argv[4]):
            print("File already exists!!")
            print("Change the name of file")
            sys.exit(0)
        fd.to_csv(sys.argv[4])
    except:
        print("File not found!!")
        print("Make sure your files are present in same directory of program file!!")
if __name__=='__main__':
    main()


import numpy as np
from matplotlib import pyplot as plt

def least_norm(A, closures, pinv=False):
    '''
        Solve: Ax = b
        Find the minimum norm vector 'x' of phases that can explain 'b' phase closures
    '''
    if pinv:
        return np.linalg.pinv(A) @ closures
    return A.T @ np.linalg.inv(A @ A.T) @ closures

def get_closures(A, phi):
    '''
        Use matrix mult to generate vector of phase closures such that
        the angle xi = phi_12 + phi_23 - phi_13
    '''
    return A @ np.angle(phi)

# Vector of phases with zero phase closure errors
closed = np.exp(1j * np.array([0.5, 1, 0.5]))

# Vector of phases with non-zero closure errors
unclosed = np.exp(1j * np.array([0.5, 1 + 0.1, 0.5 + 0.1]))

def main(phis):
    ind = np.array([1, 2, 3])
    A = np.array([[1, -1, 1]])

    # Phases to phase closures
    closures = get_closures(A, phis)

    # Phase closures back to phases
    least_norm_phi = least_norm(A, closures)
    print('Phase closures: ', closures)

    plt.plot(ind, np.angle(closed), label='observed phases')
    plt.plot(ind, np.angle(least_norm_phi), label='least norm phases ')
    plt.plot(ind, np.angle(closed * least_norm_phi.conj()),
             label='Corrected Phases')

    plt.legend(loc='lower left')
    plt.show()

main(unclosed)


import numpy as np
from scipy.optimize import curve_fit

def gauss(x,a,x0,sigma):
    return a*np.exp(-(x-x0)**2/(2*sigma**2))

def gaussian_fit(x, y, x_smooth=None, n_pts=200):
    """
    Fits a Gaussian to some data - x and y. Returns predicted interpolation values.

    Parameters
    ----------
    x: list-like
        The x values of the data to fit to.
    y: list-like
        The y values of the data to fit to.
    x_smooth: list-like
        The exact x values to interpolate for. Supercedes `n_pts`.
    n_pts: int
        The number of evenly spaced points spanning the range of `x` to interpolate for.
    """
    if x_smooth is None:
        x_smooth = np.linspace(x.min(), x.max(), n_pts)
    mean, sigma = np.nanmean(y), np.nanstd(y)
    popt,pcov = curve_fit(gauss,x,y,p0=[1,mean,sigma], maxfev=np.iinfo(np.int32).max)
    return gauss(x_smooth,*popt)

def poly_fit(x, y, degree, x_smooth=None, n_pts=200):
    """
    Fits a polynomial of any positive integer degree to some data - x and y. Returns predicted interpolation values.

    Parameters
    ----------
    x: list-like
        The x values of the data to fit to.
    y: list-like
        The y values of the data to fit to.
    x_smooth: list-like
        The exact x values to interpolate for. Supercedes `n_pts`.
    n_pts: int
        The number of evenly spaced points spanning the range of `x` to interpolate for.
    degree: int
        The degree of the polynomial to fit.
    """
    if x_smooth is None:
        x_smooth = np.linspace(x.min(), x.max(), n_pts)
    return np.array([np.array([coef*(x_val**current_degree) for coef, current_degree in
                               zip(np.polyfit(x, y, degree), range(degree, -1, -1))]).sum() for x_val in x_smooth])


import numpy as np

# softmax activation function basiccaly turn this
#
class Activation_Softmax:

    # Forward pass
    def forward(self, inputs):
        """
        Dokumentasi

        input :
        output :

        """
        # Remember input values
        self.inputs = inputs
        """
        # Get unnormalized probabilities
        # np.exp return e power given input

        # unnormalized value
        # inputs [4.8, 1.21, 2.385]
        # exponentiated valued
        # [121.51041751893969, 3.3534846525504487, 10.85906266492961]

        # for the biggest number turn zero.. anything power 0 is 1
        # e^0 (e power 0) = 1
        # normalized value to avoid big number
        # substract input with its biggest value
        # [ 0. -3.59  -2.415]
        # [1. 0.02759833 0.08936734]
        """

        exp_values = np.exp(inputs - np.max(inputs, axis=1, keepdims=True))
        """
        # what is keepdims = 1, axis = 1
        # [[4.8, 1.21, 2.385] --first sample,
        # [8.9, -1.81, 0.2] --second sample,
        # [1.41, 1.051, 0.026]] --third sample
        #np.sum(axis=1,keepdims=True) axis = 1 means sums row direction --->>
        # [[8.395] sum first sample
        # [7.29 ] sum second sample
        # [2.487]] sum third sample

        # Normalize them for each sample
        # turn this :  [121.51041751893969, 3.3534846525504487, 10.85906266492961]
        # to this : [0.89528266 0.02470831 0.08000903] --> sum = 1
        """
        probabilities = exp_values / np.sum(exp_values, axis=1, keepdims=True)
        #print(inputs)
        #print(exp_values)
        #print(probabilities)
        self.output = probabilities
        return self.output, 0

    # Backward pass
    def backward(self, dvalues):
        """
        Dokumentasi

        input :
        output :

        """
        # Create uninitialized array
        self.dinputs = np.empty_like(dvalues)

        # Enumerate outputs and gradients
        for index, (single_output, single_dvalues) in \
                enumerate(zip(self.output, dvalues)):
            # Flatten output array
            single_output = single_output.reshape(-1, 1)
            # Calculate Jacobian matrix of the output and
            jacobian_matrix = np.diagflat(single_output) - \
                              np.dot(single_output, single_output.T)

            # Calculate sample-wise gradient
            # and add it to the array of sample gradients
            self.dinputs[index] = np.dot(jacobian_matrix,single_dvalues)
        return self.dinputs


import numpy as np
from abc import ABC

class BaseModel(ABC):
    """
    Abstract Model Class used as interface of all regression models.

    :param model: Stored model data (NumPy array in most cases)
    :type model: np.ndarray
    :param data: input data for training or testing
    :type data: np.ndarray
    :param labels: labels of the input data for training
    :type labels: np.ndarray
    """

    def __init__(self):
        self.model = None

    def fit(self, data: np.ndarray, labels: np.ndarray):
        """
        :param data: input data for training
        :type data: np.ndarray
        :param labels: labels of the input data for training
        :type labels: np.ndarray
        """

        pass

    def predict(self, data: np.ndarray):
        """
        :param data: input data for testing
        :type data: np.ndarray
        :return: predicted data
        :rtype: np.ndarray
        """

        pass

class ConstantModel(BaseModel):
    """
    Constant model class that uses the average of each feature as prediction.

    :param model: Stored model data (NumPy array in most cases)
    :type model: np.ndarray
    :param data: input data for training or testing
    :type data: np.ndarray
    :param labels: labels of the input data for training
    :type labels: np.ndarray
    """

    def fit(self, data: np.ndarray, labels: np.ndarray) -> None:
        """
        Method for fitting the training data and determining and storing the model parameters. In this case
        the model returns always the data average.

        :param data: input data for training
        :type data: np.ndarray
        :param labels: labels of the input data for training
        :type labels: np.ndarray
        :return: None
        """

        w = labels.mean()
        self.model = w

    def predict(self, data: np.ndarray) -> np.ndarray:
        """
        Given the input data it returns the predicted output for each input point using the model, in this case
        the average.

        :param data: input data for testing
        :type data: np.ndarray
        :return: predicted data
        :rtype: np.ndarray
        """

        return np.ones(len(data)) * self.model

class LinearRegression(BaseModel):
    """
    Linear regression model class that uses the following model for predictions:
    .. math::
        y = \\omega*X
    """

    def fit(self, data: np.ndarray, labels: np.ndarray) -> None:
        """
        Method for fitting the training data and determining and storing the model parameters :math:`\\omega`.

        :param data: input data for training
        :type data: np.ndarray
        :param labels: labels of the input data for training
        :type labels: np.ndarray
        :return: None
        """

        if len(data.shape) == 1:
            w = data.T.dot(labels) / data.T.dot(data)
        else:
            w = np.linalg.inv(data.T.dot(data)).dot(data.T).dot(labels)
        self.model = w

    def predict(self, data: np.ndarray) -> np.ndarray:
        """
        Given the input data it returns the predicted output for each input point using the model, in this case:

        .. math::
            y = \\omega*X

        :param data: input data for testing
        :type data: np.ndarray
        :return: predicted data
        :rtype: np.ndarray
        """

        return self.model * data

class LinearRegressionWithB(BaseModel):
    """
    Affine regression model class that uses the following model for predictions:

    .. math::
        y = \\omega*X + b
    """

    def fit(self, data: np.ndarray, labels: np.ndarray) -> None:
        """
        Method for fitting the training data and determining and storing the model parameters :math:`\\omega` and b.

        :param data: input data for training
        :type data: np.ndarray
        :param labels: labels of the input data for training
        :type labels: np.ndarray
        :return: None
        """

        x_expanded = np.vstack((data, np.ones(len(data)))).T
        w = np.linalg.inv(x_expanded.T.dot(x_expanded)).dot(x_expanded.T).dot(labels)
        self.model = w

    def predict(self, data: np.ndarray) -> np.ndarray:
        """
        Given the input data it returns the predicted output for each input point using the model, in this case:

        .. math::
            y = \\omega*X + b

        :param data: input data for testing
        :type data: np.ndarray
        :return: predicted data
        :rtype: np.ndarray
        """

        x_expanded = np.vstack((data, np.ones(len(data)))).T
        return x_expanded.dot(self.model)


# swing up of the inverted dual pendulum with partial linearization

# import trajectory class and necessary dependencies
from pytrajectory import TransitionProblem
from sympy import cos, sin
import numpy as np

def f(xx, uu, uuref, t, pp):
    """ Right hand side of the vectorfield defining the system dynamics

    :param xx:       state
    :param uu:       input
    :param uuref:    reference input (not used)
    :param t:        time (not used)
    :param pp:       additionial free parameters  (not used)

    :return:        xdot
    """
    x1, x2, x3, x4, x5, x6 = xx  # system variables
    uu, = uu                      # input variable

    # length of the pendulums
    l1 = 0.7
    l2 = 0.5

    g = 9.81    # gravitational acceleration

    ff = np.array([x2,
                   uu,
                   x4,
                   (1/l1)*(g*sin(x3) + uu*cos(x3)),
                   x6,
                   (1/l2)*(g*sin(x5) + uu*cos(x5))
                   ])

    return ff

# system state boundary values for a = 0.0 [s] and b = 2.0 [s]
xa = [0.0, 0.0,  np.pi, 0.0,  np.pi, 0.0]
xb = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

# boundary values for the input
ua = [0.0]
ub = [0.0]

# create trajectory object
S = TransitionProblem(f, a=0.0, b=2.0, xa=xa, xb=xb, ua=ua, ub=ub)

# alter some method parameters to increase performance
S.set_param('su', 10)
S.set_param('eps', 8e-2)

# run iteration
S.solve()

# the following code provides an animation of the system above
# for a more detailed explanation have a look at the 'Visualisation' section in the documentation
import sys
import matplotlib as mpl
from pytrajectory.visualisation import Animation

def draw(xti, image):
    x, phi1, phi2 = xti[0], xti[2], xti[4]

    l1 = 0.7
    l2 = 0.5

    car_width = 0.05
    car_heigth = 0.02
    pendel_size = 0.015

    x_car = x
    y_car = 0

    x_pendel1 = -l1*sin(phi1)+x_car
    y_pendel1 = l1*cos(phi1)

    x_pendel2 = -l2*sin(phi2)+x_car
    y_pendel2 = l2*cos(phi2)

    # pendulums
    sphere1 = mpl.patches.Circle((x_pendel1,y_pendel1),pendel_size,color='k')
    sphere2 = mpl.patches.Circle((x_pendel2,y_pendel2),pendel_size,color='0.3')

    # car
    car = mpl.patches.Rectangle((x_car-0.5*car_width,y_car-car_heigth),car_width,car_heigth,fill=True,facecolor='0.75',linewidth=2.0)

    # joint
    joint = mpl.patches.Circle((x_car,0),0.005,color='k')

    # rods
    rod1 = mpl.lines.Line2D([x_car,x_pendel1],[y_car,y_pendel1],color='k',zorder=1,linewidth=2.0)
    rod2 = mpl.lines.Line2D([x_car,x_pendel2],[y_car,y_pendel2],color='0.3',zorder=1,linewidth=2.0)

    image.patches.append(sphere1)
    image.patches.append(sphere2)
    image.patches.append(car)
    image.patches.append(joint)
    image.lines.append(rod1)
    image.lines.append(rod2)

    return image

if not 'no-pickle' in sys.argv:
    # here we save the simulation results so we don't have to run
    # the iteration again in case the following fails
    S.save(fname='ex2_InvertedDualPendulumSwingUp.pcl')

if 'plot' in sys.argv or 'animate' in sys.argv:
    A = Animation(drawfnc=draw, simdata=S.sim_data,
                  plotsys=[(0,'x'),(2,'phi1'),(4,'phi2')], plotinputs=[(0,'u')])

    xmin = np.min(S.sim_data[1][:,0])
    xmax = np.max(S.sim_data[1][:,0])
    A.set_limits(xlim=(xmin - 1.0, xmax + 1.0), ylim=(-0.8,0.8))

if 'plot' in sys.argv:
    A.show(t=S.b)

if 'animate' in sys.argv:
    A.animate()
    A.save('ex2_InvertedDualPendulumSwingUp.gif')


import csv
from matplotlib import pyplot
import numpy as np
import os
import sys

xmin, xmax = np.float64(-2.5), np.float64(1.0)
ymin, ymax = np.float64(-1.25), np.float64(1.25)
nx = int(os.environ.get('INPUTMAT_ROWS'))
ny = int(os.environ.get('INPUTMAT_COLS'))
maxiter = 100

def mandelbrotorbit(c):
    z = complex(0, 0) + c
    for n in range(maxiter):
        if abs(z) > 2:
            return n
        z = z*z + c
    return maxiter

def linspace(start, end, n):
    lspace = [start]
    distance = (end - start) / np.float64(n - 1)
    next = start
    while np.abs(next - end) > 0.000000000001:
        next += distance
        lspace.append(next)
    return lspace

X = linspace(xmin, xmax, nx)
Y = linspace(ymin, ymax, ny)

def mandelbrot(x):
    Z = [complex(x, y) for y in Y]
    return list(map(mandelbrotorbit, Z))

N = list(map(mandelbrot, X))

def matrix_to_csv(m):
    filename = 'output-py-seq-{}.csv'.format(nx)
    with open(filename, 'w') as f:
        writer = csv.writer(f, delimiter=';', lineterminator='\n')
        writer.writerows(N)

if '-export' in sys.argv:
    matrix_to_csv(N)

if '-fractal' in sys.argv:
    pyplot.imshow(N)
    pyplot.savefig('mandel.png')


import numpy as np

def unit_vector(vector):
    """ Returns the unit vector of the vector.  """
    return vector / np.linalg.norm(vector)

def angle_between(v1, v2):
    """ Returns the angle in radians between vectors 'v1' and 'v2'::

            >>> angle_between((1, 0, 0), (0, 1, 0))
            1.5707963267948966
            >>> angle_between((1, 0, 0), (1, 0, 0))
            0.0
            >>> angle_between((1, 0, 0), (-1, 0, 0))
            3.141592653589793
    """
    v1_u = unit_vector(v1)
    v2_u = unit_vector(v2)
    return (180 / np.pi) * np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))

def distance_between(v1, v2):
    return np.linalg.norm(np.asarray(v1) - np.asarray(v2))

def heron(a,b,c):
    s = (a + b + c) / 2
    area = (s*(s-a) * (s-b)*(s-c)) ** 0.5
    return area

def area_triangle(v1, v2, v3):
    a = distance_between(v1, v2)
    b = distance_between(v1, v3)
    c = distance_between(v2, v3)
    A = heron(a,b,c)
    return A


import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

T = 5
Fs = 400.0
n = T * Fs

f1 = 10
f2 = 25
f3 = 50
f4 = 100

t1 = np.linspace(0, T, n)
x1 = np.cos(2 * np.pi * f1 * t1)
t2 = np.linspace(T, 2 * T, n)
x2 = np.cos(2 * np.pi * f2 * t2)
t3 = np.linspace(2 * T, 3 * T, n)
x3 = np.cos(2 * np.pi * f3 * t3)
t4 = np.linspace(3 * T, 4 * T, n)
x4 = np.cos(2 * np.pi * f4 * t4)

x = np.hstack((x1, x2, x3, x4))
t = np.hstack((t1, t2, t3, t4))

TWs = [25e-3, 100e-3, 500e-3, 1000e-3, 2000e-3, 3000e-3]
NWs = []
npersegs = []
for TW in TWs:
    NW = int(TW * Fs)
    NWs.append(NW)
    npersegs.append(NW)

windows = []
windows.append(signal.gaussian(NWs[0], std=30))
windows.append(signal.gaussian(NWs[1], std=30))
windows.append(signal.gaussian(NWs[2], std=30))
windows.append(signal.gaussian(NWs[3], std=30))
windows.append(signal.gaussian(NWs[4], std=30))
windows.append(signal.gaussian(NWs[5], std=30))

noverlap = 1
nfft = 2048

print(t.shape, x.shape)

plt.figure()
plt.plot(t, x)

plt.figure()

cnt = 1
for window, nperseg in zip(windows, npersegs):
    # print(window)

    # (x, fs=1.0, window=('tukey', 0.25), nperseg=None, noverlap=None, nfft=None, detrend='constant', return_onesided=True, scaling='density', axis=-1, mode='psd')
    # [F, T, S] = signal.spectral.spectrogram(x, np.hamming(1024), nperseg=1024, noverlap=0, detrend=False, return_onesided=True, mode='magnitude')
    [F, T, S] = signal.spectral.spectrogram(x, fs=Fs, window=window, nperseg=nperseg, noverlap=noverlap,
                                            nfft=nfft, detrend=False, return_onesided=True,
                                            scaling='density', mode='psd')

    print('T: ', T.shape, 'F:', F.shape, 'S:', S.shape)

    plt.subplot(2, 3, cnt)
    map = plt.pcolormesh(T, F, S, cmap='jet')
    plt.ylabel('Frequency/Hz')
    plt.xlabel('Time/s')
    plt.axis('tight')
    plt.title('STFT->' + 'Gauss window size:' + str(TWs[cnt-1]) + 's')
    cb = plt.colorbar(cax=None, ax=None, shrink=0.5)
    cnt = cnt + 1
plt.show()


'''
Shortest Path in a Weighted Directed Graph Using Dynamic Programming.

Solution uses vectorization compared to the solution given in the lecture notes.
'''

import numpy as np
from numpy import inf

Q = np.array([[inf, 1,   5,   3,   inf, inf, inf],
              [inf, inf, inf, 9,   6,   inf, inf],
              [inf, inf, inf, inf, inf, 2,   inf],
              [inf, inf, inf, inf, inf, 4,   8],
              [inf, inf, inf, inf, inf, inf, 4],
              [inf, inf, inf, inf, inf, inf, 1],
              [inf, inf, inf, inf, inf, inf, 0]])

num_nodes = 7
J_n = [0 for _ in range(num_nodes)]
J_next = [0 for _ in range(num_nodes)]
n = 0
i, max_iter = 0, 500

while i < max_iter:
    min_cost = np.min(Q + J_n, axis=1)
    J_next = min_cost

    if np.all(J_next == J_n):
        break

    J_n = J_next
    i += 1

print(J_n)
print(J_n[0])


"""
metric.py
Based on
https://github.com/rshk/elo/blob/master/elo.py
"""

import numpy as np

def elo_expected(A, B):
    """
    Calculate expected score of A in a match against B
    :param A: Elo rating for player A
    :param B: Elo rating for player B
    """
    return 1. / (1 + 10 ** ((B - A) / 400.))

def get_elo_score(old, exp, score, k=32):
    """
    Calculate the new Elo rating for a player
    :param old: The previous Elo rating
    :param exp: The expected score for this match
    :param score: The actual score for this match
    :param k: The k-factor for Elo (default: 32)
    """
    return int(old + k * (score - exp))

def elo(a_score, b_score, results, k=32):
    """
    Return an elo score for players a and b according to results
    a_score : int
        elo score of a
    b_score : int
        elo score of b
    results : x, list of xs, np.ndarray of xs
        where x is in [0, 0.5, 1]
        results from game, where 0 is loss for a,
        0.5 is draw, 1 is win for a. Ignores values that are not above

    Returns
    new_a_score : int
        new elo score for a
    new_b_score : int
        new elo score for b
    """
    # convert to list
    if not isinstance(results, (list, np.ndarray)):
        results = [results]

    new_a_score = a_score
    new_b_score = b_score

    allowed_results = [0, 0.5, 1]
    for result in results:
        if result not in allowed_results: continue

        exp_a = elo_expected(new_a_score, new_b_score)
        exp_b = elo_expected(new_b_score, new_a_score)

        new_a_score = get_elo_score(new_a_score, exp_a, result, k=k)
        new_b_score = get_elo_score(new_b_score, exp_b, 1 - result, k=k)

    return new_a_score, new_b_score


"""
iterfast
====

Provides NumPy Arrays
  1. of some commonly used sequences and series
     eg. A sequence of prime numbers.
  2. in least possible time.
  3. that may take time to achieve manually.

How to use the documentation
----------------------------
Documentation is available in two forms: docstrings provided
with the code, and a loose standing reference guide, available from
`the iterfast homepage <https://https://github.com/pradipbankar0097/iterfast/docs/index.html>`_.

"""

import math
import numpy
def getprimes(upto=1000000):
    """
    Parameters
    ----------
    1. upto : The upper bound for the required sequence of prime numbers.

    Returns
    -------
    A numpy.ndarray of all prime numbers upto 'upto' inclusive.
    """
    if upto<2:
        return numpy.ndarray(0)
    primes=numpy.arange(3,upto+1,2)
    isprime=numpy.ones(int((upto-1)/2),dtype=bool)
    for factor in primes[:int(math.sqrt(upto))]:
        if isprime[int((factor-2)/2)]:
            isprime[int((factor*3-2)/2)::int(factor)]=0
    return numpy.insert(primes[isprime],0,2).copy()


import numpy as np
from scipy.stats import uniform
import random, math
from statistics import mean
import matplotlib.pyplot as plt

# Question 1.2
# Calculate the integral of cos(x)dx in (0, 2) interval
random.seed(0)
f_estimates = [None]*50
f_std = [None]*50

for i in range(1, 51):
    random_array = uniform.rvs(size = i*1000, scale=2)
    f_values_array = np.cos(random_array)*2
    f_estimates[i-1] = np.mean(f_values_array)
    f_std[i-1] = np.std(f_values_array/np.sqrt(i*1000))

# Question 1.3
analytical_value = math.sin(2) - math.sin(0)

plt.plot(f_estimates, ".")
plt.plot(mean(f_estimates)+np.array(f_std)*3)
plt.plot(mean(f_estimates)-np.array(f_std)*3)
plt.plot([analytical_value]*50, "x")
plt.show()


#!/usr/bin/env python3
import sys

import numpy as np

from multiprocessing import cpu_count, Pool

np.random.seed(2017)

def inside_circle(total_count):

    x = np.float32(np.random.uniform(size=total_count))
    y = np.float32(np.random.uniform(size=total_count))

    radii = np.sqrt(x*x + y*y)

    count = len(radii[np.where(radii<=1.0)])

    return count

def estimate_pi(n_samples,n_cores):

    partitions = [ ]
    for i in range(n_cores):
        partitions.append(int(n_samples/n_cores))

    pool = Pool(processes=n_cores)
    counts=pool.map(inside_circle, partitions)

    total_count = sum(partitions)
    return (4.0 * sum(counts) / total_count)

if __name__=='__main__':

    ncores = cpu_count()
    n_samples = 10000
    if len(sys.argv) > 1:
        n_samples = int(sys.argv[1])

    partitions = [ int(n_samples/ncores) for item in range(ncores)]

    sizeof = np.dtype(np.float32).itemsize

    my_pi = estimate_pi(n_samples,ncores)

    print("[parallel version] required memory %.3f MB" % (n_samples*sizeof*3/(1024*1024)))
    print("[using %3i cores ] pi is %f from %i samples" % (ncores,my_pi,n_samples))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Jul 10 10:57:16 2021

@author: alessandro
"""

import math
import numpy as np
import matplotlib.pyplot as plt

u = []
for i in range(1, 36):
    u.append((15 * ((3/5) ** i + 1)) / (5 * (3/5) ** i + 3))

print(u)

u1 = [4]
for i in range(1, 35):
    u1.append(8 - (15 / (u1[i - 1])))
print(u1)

u2 = [4, 17/4]
for i in range(2, 35):
    u2.append(108 - (815 / u2[i - 1]) + (1500 / (u2[i - 1] * u2[i - 2])))
print(u2)

u = np.array(u)
u1 = np.array(u1)
u2 = np.array(u2)

eu1 = np.abs(u1 - u)
eu2 = np.abs(u2 - u)
x = np.arange(1, 36)
plt.semilogy(x, eu1, label="Errore u1")
plt.semilogy(x, eu2, label="Errore u2")
plt.legend()
plt.show()

# Punti fissi
def iterazione(g, x0, tolx, nmax=2048):
    x = g(x0)
    it, xk = 1, [x]
    while it < nmax and abs(x - x0) > tolx * abs(x):
        x0 = x
        x = g(x0)
        xk.append(x)
        it += 1
    return x, it, xk

def g1(x): return 8 - 15/x
def g2(x): return 108 - 815/x + 1500/(x**2)

def dg1(x): return 15 / (x ** 2)
def dg2(x): return 815 / (x ** 2) - 1500 / (x ** 3)

xx = np.arange(1, 110)
plt.title("g1(x)")
plt.ylim(-5, 10)
plt.plot(xx, xx)
plt.plot(xx, g1(xx), label="g1(x)")
plt.plot(xx, dg1(xx), label="g1'(x)")
plt.plot([5], [g1(5)], 'o')
plt.plot([5], [dg1(5)], 'o')
plt.legend()
plt.show()

plt.title("g2(x)")
plt.ylim(-5, 110)
plt.plot(xx, xx)
plt.plot(xx, g2(xx), label="g2(x)")
plt.plot(xx, dg2(xx), label="g2'(x)")
plt.plot([5], [g2(5)], 'o')
plt.plot([5], [dg2(5)], 'o')
plt.plot([100], [g2(100)], 'o')
plt.plot([100], [dg2(100)], 'o')
plt.legend()
plt.show()

punto, it, xk = iterazione(g1, 1, 1e-12)
print(f"g1 => {punto} con {it} iterazioni")

punto, it, xk = iterazione(g2, 1, 1e-12)
print(f"g2 => {punto} con {it} iterazioni")


# Do not import any additional 3rd party external libraries as they will not
# be available to AutoLab and are not needed (or allowed)
import numpy as np

class Activation(object):

    """
    Interface for activation functions (non-linearities).
    """

    def __init__(self):
        self.state = None

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

    def forward(self, x):
        raise NotImplemented

    def derivative(self):
        raise NotImplemented

class Sigmoid(Activation):

    """
    Sigmoid activation function
    """

    def __init__(self):
        super(Sigmoid, self).__init__()

    def forward(self, x):
        self.state = (1 / (1 + np.exp(-x)))
        return self.state

    def derivative(self):
        return (self.state) * (1 - self.state)

class Tanh(Activation):

    """
    Modified Tanh to work with BPTT.
    The tanh(x) result has to be stored elsewhere otherwise we will
    have to store results for multiple timesteps in this class for each cell,
    which could be considered bad design.

    Now in the derivative case, we can pass in the stored hidden state and
    compute the derivative for that state instead of the "current" stored state
    which could be anything.
    """

    def __init__(self):
        super(Tanh, self).__init__()

    def forward(self, x):
        self.state = np.tanh(x)
        return self.state

    def derivative(self, state=None):
        if state is not None:
            return 1 - (state**2)
        else:
            return 1 - (self.state**2)


#! /usr/bin/python3
"""
Generate/plot a spiral.

If output of image is desired, include any string as a
command line argument.

"""
import sys

import matplotlib.pyplot as plt
import numpy as np

#### Spiral Parameters ####
xCenter = 2.0
yCenter = 4.0
nPts = 300
                   # Reverse values for inward spiral
radius0 = 2.0      # Initial radius
radiusF = 5.0      # Final radius
nTurns = 3         # Number of turns
theta0_deg = 45.0  # Initial rotation angle, degrees
###########################

if len(sys.argv) == 2:
    outFlag = True
else:
    outFlag = False

fig = plt.figure(facecolor='lightgrey')
ax = fig.add_subplot(111)
ax.patch.set_facecolor('black')

ax.set_aspect('equal')
ax.grid(True, which='both')

# Insert X and Y axes
ax.axhline(y=0, color='w')
ax.axvline(x=0, color='w')

# Remove #'s to suppress tick labels
#ax.set_xticklabels([])
#ax.set_yticklabels([])

# Radius growth rate across total number of turns
b = (radiusF-radius0)/(2.0*np.pi*nTurns)

# Convert initial rotation angle to radians
theta0 = theta0_deg*np.pi/180.0
# Determine final rotation angle across total number of turns
thetaF = 2.0*np.pi*nTurns + theta0

# Array of incremental angles
t = np.arange(theta0, thetaF, (thetaF-theta0)/nPts, dtype=float)

# (x,y) coordinates of individual points on the spiral
x = (radius0+b*t)*np.cos(t)+xCenter
y = (radius0+b*t)*np.sin(t)+yCenter

print('len(x) = ', len(x))

print('xmin = {0:8.2f}  xmax = {1:8.2f}'.format(min(x), max(x)))
print('ymin = {0:8.2f}  ymax = {1:8.2f}'.format(min(y), max(y)))

# s is marker size
ax.scatter(x, y, marker='o', s=4.0, color='red')

# Conditionally output image
if outFlag == True:
    fig.savefig('genSpiral.png', facecolor='lightgrey', format='png')

plt.show()


# -*- coding: utf-8 -*-
"""
ese9
"""

import numpy as np
import interpolL as fz
import math

def zeri_Cheb(a,b,n):
    t1=(a+b)/2
    t2=(b-a)/2
    x=np.zeros((n+1,))
    for k in range(n+1):
        x[k]=t1+t2*np.cos(((2*k+1)/(2*(n+1))*math.pi))

    return x

#calcolo della costante di lebesgue in [-1,1]

xx=np.linspace(-1,1,200);
LLe = np.zeros((4,1))
LLc = np.zeros((4,1))
l = 0
for n in range(5,25,5):
    xC = zeri_Cheb(-1, 1, n)
    xE = np.linspace(-1, 1, n+1)
    Le = np.zeros((200,1))
    Lc = np.zeros((200,1))
    for i in range(n+1):
        lagrC = fz.polinomioLagrange(xC, i)
        lagrE = fz.polinomioLagrange(xE, i)
        Le = Le + np.abs(np.polyval(lagrE, xx))
        Lc = Lc + np.abs(np.polyval(lagrC, xx))

    LLe[l] = np.max(Le)
    LLc[l] = np.max(Lc)
    l += 1

print("Costante di Lebesgue con nodi equispaziati ", LLe)
print("Costante di Lebesgue con nodi di Cheb ", LLc)


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#Scipy库中的optimiz可以实现matlab中fminunc的功能，来优化函数计算成本和梯度
import scipy.optimize as opt
#高级处理分类的一个信息report
from sklearn.metrics import classification_report as cr

#=================visualizing data
path = 'E:\lessons\ML wu.n.g\coursera-ml-py-master\coursera-ml-py-master\machine-learning-ex2\ex2\ex2data2.txt'
data2 = pd.read_csv(path, names = ['Test1', 'Test2', 'Accepter'])
#print(data2.head())
def plot_data():
    positive = data2[data2.Accepter.isin([1])]
    negative = data2[data2.Accepter.isin([0])]
    fig ,ax = plt.subplots(figsize = (8,8))
    ax.scatter(positive['Test1'], positive['Test2'], s=50, c = 'b', marker = 'o', label = 'good')
    ax.scatter(negative['Test1'], negative['Test2'], s=50, c = 'r', marker = 'x', label = 'bad')
    ax.legend()
    ax.set_xlabel('Test 1 Score')
    ax.set_ylabel('Test 2 Score')
    ax.set_title('Data2')

plot_data()
#plt.show()

#=============feature mapping

#经过映射后，将只有两个特征的向量转换成为有28个特征的特征向量，故可以产生一个更复杂的边界
def feature_mapping(x1, x2, power):
    data={}
    #range()函数也不包括最后一个数
    for i in range(power+1):
        for p in range(i+1):
            # format前面是'.' 不是','!!!!!!!!!!!!!!
           data["f{}{}".format(i - p, p)] = np.power(x1, i - p) * np.power(x2, p)
    return pd.DataFrame(data)
x1 = data2['Test1'].as_matrix()
x2 = data2['Test2'].as_matrix()
ndata2 = feature_mapping(x1, x2, power = 6)

#==============Regularized CostFunction

def sigmoid(z):
    return 1 / (1 + np.exp(-z))
def cost(theta , X, Y):
    first = (-Y) * np.log(sigmoid(X @ theta))
    second = (1 - Y) * np.log(1 - sigmoid(X @ theta))
    return np.mean(first - second)
#X中已经包含1向量，故无需添加
X = ndata2.as_matrix()
Y = data2['Accepter'].as_matrix()
theta = np.zeros(X.shape[1]).reshape(-1)
#print(X.shape,Y.shape,theta.shape)
def costReg(theta, X, Y, l=1):
    ntheta = theta[1:, ]
    #补偿项
    reg = (l / (2*len(X))) * (ntheta @  ntheta.T)
    return cost(theta, X, Y) + reg
print(costReg(theta, X, Y, l=1))

#==============Regularized Gradient

def gradient(theta, x, y):
     return (x.T @ (sigmoid(x @ theta) -y)) / len(y)
def gradientReg(theta, x, y, l=1):
    reg = (1 / len(y)) * theta
    reg[0] = 0
    return gradient(theta, x, y) + reg
#gradientReg(theta, X, Y, l=1)
#print(gradientReg(theta, X, Y))

#============Learning Parameters(theta)

'''
result2 = opt.fmin_tnc(func = costReg, x0 = theta, fprime = gradientReg, args=(X, Y, 2))
print(result2)
'''
#print(theta, theta.shape)
#print(X.shape, X, Y.shape, Y)
#逆矩阵操作
B = np.linalg.inv(X.T @ X)
final_theta = B @ X.T @ Y
print(final_theta, final_theta.shape)

'''高级库使用发放
from sklearn import linear_model#调用sklearn的线性回归包
model = linear_model.LogisticRegression(penalty='l2', C=1.0)
model.fit(X, y.ravel())
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
          intercept_scaling=1, max_iter=100, multi_class='ovr', n_jobs=1,
          penalty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False)
model.score(X, y)  # 0.8305084745762712
'''
#============Evaluating

def predict(theta, X):
     probability = sigmoid(X @ theta)
     return [1 if x >= 0.5 else 0 for x in probability]
'''
final_theta = result2[0]
'''
predictions = predict(final_theta, X)
correct = [1 if a==b else 0 for (a,b) in zip(predictions, Y)]
#准确度
acc = sum(correct) / len(correct)
print(acc)

#===========Decision Boundary
x = np.linspace(-1,1.5,250)
#生成xx yy坐标 利用meshgrid生成二维数组，在用ravel()变成一维数组
xx, yy = np.meshgrid(x, x)
z = feature_mapping(xx.ravel(), yy.ravel(), 6).as_matrix()
print(z.shape)
z = z @ final_theta
#z一定要和xx，yy保持一样的格式
print(z.shape,final_theta.shape,xx.shape)
z= z.reshape(xx.shape)
plot_data()
# 0 表示只画出一条线 默认画出z=0？？？
contour = plt.contour(xx, yy, z, 0 )
plt.clabel(contour,fontsize=10,colors=('k'))
plt.ylim(-0.8, 1.2)
plt.show()


# DFT analyse task
#
# 	1) generate periodic triangular signals of various frequencies, and analyse amplitude spectrum
#
# 	2) pronounce any vowel sound(s) and record your voice, convert recording to 16 bit wav, and
# 	analyse spectrum of your voice (find main frequencies of your voice)
#
# below you can see the implementation of sinusoidal signal

import numpy as np
import scipy.io.wavfile as wavfile
import time
import os
import matplotlib.pyplot as plt
import matplotlib.colors as colors
from matplotlib.mlab import bivariate_normal
import glob

#--------- parameters -----------------------------------------
file_name = 'sinusoid.wav'
sampling_rate = 16000 # hz
omega = np.pi / 10 # radians per sample (pysical_frequency = sampling_rate * omega / (2*np.pi))
amplitude = 1000
N = 3 * sampling_rate # lenght of signal

coef_no = int(N / 2) + 1 # amount of independent coefficients
samples = np.array(list(range(N))) # sample indices
freqs = np.array(list(range(coef_no))) * sampling_rate / N # frequencies of current signal spectrum

#--------generating signal ------------------------------------
sinusoid = amplitude*np.sin(omega * samples) # sinusoidal signal
sinusoid = sinusoid.astype('int16')
wavfile.write(file_name, sampling_rate, sinusoid)
print(freqs)

coefs_sinusoid = np.fft.rfft(sinusoid) # DFT coefs for 0, 1, ..., floor(N/2) base vectors
amplitude_spectr = np.abs(coefs_sinusoid)
db_spectr = 10*np.log10(amplitude_spectr + 1)

#-------------- visualising amplitude spectrum -----------------
plt.plot(freqs, amplitude_spectr)
plt.xlabel('freqs in hz')
plt.ylabel('amplituds')
plt.show()

Classes/Junk Code 2019 10 03/DFT_analys.py


import numpy as np
from sympy import *
from scipy.optimize import approx_fprime

x = symbols('x')
y = symbols('y')

# first function
f = 2 * x ** 2 * y ** 3 + 1 / x + y ** 2 * x + 7
f1x = diff(f, x)
print(format(f1x))

f1y = diff(f, y)
print(format(f1y))

# second function
f = x ** 2 * y - sin(x * y) + cos(x ** 2) + 6 * y
f1x = diff(f, x)
print(format(f1x))

f1y = diff(f, y)
print(format(f1y))

# gradient of the first function
def func(t):
    return 2 * t[0] ** 2 * t[1] ** 3 + 1 / t[0] + t[1] ** 2 * t[0] + 7

eps = np.sqrt(np.finfo(float).eps)
grad = approx_fprime([1, 2], func, [eps, eps])
print(grad)


import numpy as np

__author__ = "Lei Hu <hulei@pmo.ac.cn>"
__version__ = "v1.0"

# * Remarks on Convolution Theorem
#    NOTE on Symbols: L theoretically can be even / odd, recall w = (L-1)//2 & w' = L//2 and w+w' = L-1
#    a. To make use of FFT with convolution theorem, it is necessary to convert convolution-kernel
#        with relatively small size by Circular-Shift & tail-Zero-padding (CSZ) to align the Image-Size.
#    b. If we have an image elementwise-multiplication FI * FK, where FI and FK are conjugate symmetric,
#        Now we want to get its convolution counterpart in real space, we can calculate the convolution kernel by iCSZ on IDFT(FK).
#        In this process, we have to check the lost weight by size truncation, if the lost weight is basically inappreciable,
#        the equivalent convolution is a good approximation.

class ConvKernel_Convertion:
    def CSZ(ConvKernel, N0, N1):
        L0, L1 = ConvKernel.shape
        w0, w1 = (L0-1) // 2, (L1-1) // 2
        pd0, pd1 = N0 - L0, N1 - L1
        TailZP = np.lib.pad(ConvKernel, ((0, pd0), (0, pd1)), 'constant', constant_values=(0, 0))    # Tail-Zero-Padding
        KIMG_CSZ = np.roll(np.roll(TailZP, -w0, axis=0), -w1, axis=1)    # Circular-Shift
        return KIMG_CSZ

    def iCSZ(KIMG, L0, L1):
        N0, N1 = KIMG.shape
        w0, w1 = (L0-1) // 2, (L1-1) // 2
        KIMG_iCSZ = np.roll(np.roll(KIMG, w1, axis=1), w0, axis=0)    # inverse Circular-Shift
        ConvKernel = KIMG_iCSZ[:L0, :L1]    # Tail-Truncation
        lost_weight = 1.0 - np.sum(np.abs(ConvKernel)) / np.sum(np.abs(KIMG_iCSZ))
        print('MeLOn CheckPoint: Tail-Truncation Lost-Weight [%.4f %s] (Absolute Percentage Error) ' %(lost_weight*100, '%'))
        return ConvKernel