"""
==================================
The Tipping Problem - The Hard Way
==================================

 Note: This method computes everything by hand, step by step. For most people,
 the new API for fuzzy systems will be preferable. The same problem is solved
 with the new API `in this example <./plot_tipping_problem_newapi.html>`_.

The 'tipping problem' is commonly used to illustrate the power of fuzzy logic
principles to generate complex behavior from a compact, intuitive set of
expert rules.

Input variables
---------------

A number of variables play into the decision about how much to tip while
dining. Consider two of them:

* ``quality`` : Quality of the food
* ``service`` : Quality of the service

Output variable
---------------

The output variable is simply the tip amount, in percentage points:

* ``tip`` : Percent of bill to add as tip

For the purposes of discussion, let's say we need 'high', 'medium', and 'low'
membership functions for both input variables and our output variable. These
are defined in scikit-fuzzy as follows

"""
import numpy as np
import skfuzzy as fuzz
import matplotlib.pyplot as plt

# Generate universe variables
#   * Quality and service on subjective ranges [0, 10]
#   * Tip has a range of [0, 25] in units of percentage points
x_qual = np.arange(0, 11, 1)
x_serv = np.arange(0, 11, 1)
x_tip = np.arange(0, 26, 1)

# Generate fuzzy membership functions
qual_lo = fuzz.trimf(x_qual, [0, 0, 5])
qual_md = fuzz.trimf(x_qual, [0, 5, 10])
qual_hi = fuzz.trimf(x_qual, [5, 10, 10])
serv_lo = fuzz.trimf(x_serv, [0, 0, 5])
serv_md = fuzz.trimf(x_serv, [0, 5, 10])
serv_hi = fuzz.trimf(x_serv, [5, 10, 10])
tip_lo = fuzz.trimf(x_tip, [0, 0, 13])
tip_md = fuzz.trimf(x_tip, [0, 13, 25])
tip_hi = fuzz.trimf(x_tip, [13, 25, 25])

# Visualize these universes and membership functions
fig, (ax0, ax1, ax2) = plt.subplots(nrows=3, figsize=(8, 9))

ax0.plot(x_qual, qual_lo, 'b', linewidth=1.5, label='Bad')
ax0.plot(x_qual, qual_md, 'g', linewidth=1.5, label='Decent')
ax0.plot(x_qual, qual_hi, 'r', linewidth=1.5, label='Great')
ax0.set_title('Food quality')
ax0.legend()

ax1.plot(x_serv, serv_lo, 'b', linewidth=1.5, label='Poor')
ax1.plot(x_serv, serv_md, 'g', linewidth=1.5, label='Acceptable')
ax1.plot(x_serv, serv_hi, 'r', linewidth=1.5, label='Amazing')
ax1.set_title('Service quality')
ax1.legend()

ax2.plot(x_tip, tip_lo, 'b', linewidth=1.5, label='Low')
ax2.plot(x_tip, tip_md, 'g', linewidth=1.5, label='Medium')
ax2.plot(x_tip, tip_hi, 'r', linewidth=1.5, label='High')
ax2.set_title('Tip amount')
ax2.legend()

# Turn off top/right axes
for ax in (ax0, ax1, ax2):
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.get_xaxis().tick_bottom()
    ax.get_yaxis().tick_left()

plt.tight_layout()

"""
.. image:: PLOT2RST.current_figure

Fuzzy rules
-----------

Now, to make these triangles useful, we define the *fuzzy relationship*
between input and output variables. For the purposes of our example, consider
three simple rules:

1. If the food is bad OR the service is poor, then the tip will be low
2. If the service is acceptable, then the tip will be medium
3. If the food is great OR the service is amazing, then the tip will be high.

Most people would agree on these rules, but the rules are fuzzy. Mapping the
imprecise rules into a defined, actionable tip is a challenge. This is the
kind of task at which fuzzy logic excels.

Rule application
----------------

What would the tip be in the following circumstance:

* Food *quality* was **6.5**
* *Service* was **9.8**

"""
#
# # We need the activation of our fuzzy membership functions at these values.
# # The exact values 6.5 and 9.8 do not exist on our universes...
# # This is what fuzz.interp_membership exists for!
# qual_level_lo = fuzz.interp_membership(x_qual, qual_lo, 6.5)
# qual_level_md = fuzz.interp_membership(x_qual, qual_md, 6.5)
# qual_level_hi = fuzz.interp_membership(x_qual, qual_hi, 6.5)
#
# serv_level_lo = fuzz.interp_membership(x_serv, serv_lo, 9.8)
# serv_level_md = fuzz.interp_membership(x_serv, serv_md, 9.8)
# serv_level_hi = fuzz.interp_membership(x_serv, serv_hi, 9.8)
#
# # Now we take our rules and apply them. Rule 1 concerns bad food OR service.
# # The OR operator means we take the maximum of these two.
# active_rule1 = np.fmax(qual_level_lo, serv_level_lo)
#
# # Now we apply this by clipping the top off the corresponding output
# # membership function with `np.fmin`
# tip_activation_lo = np.fmin(active_rule1, tip_lo)  # removed entirely to 0
#
# # For rule 2 we connect acceptable service to medium tipping
# tip_activation_md = np.fmin(serv_level_md, tip_md)
#
# # For rule 3 we connect high service OR high food with high tipping
# active_rule3 = np.fmax(qual_level_hi, serv_level_hi)
# tip_activation_hi = np.fmin(active_rule3, tip_hi)
# tip0 = np.zeros_like(x_tip)
#
# # Visualize this
# fig, ax0 = plt.subplots(figsize=(8, 3))
#
# ax0.fill_between(x_tip, tip0, tip_activation_lo, facecolor='b', alpha=0.7)
# ax0.plot(x_tip, tip_lo, 'b', linewidth=0.5, linestyle='--', )
# ax0.fill_between(x_tip, tip0, tip_activation_md, facecolor='g', alpha=0.7)
# ax0.plot(x_tip, tip_md, 'g', linewidth=0.5, linestyle='--')
# ax0.fill_between(x_tip, tip0, tip_activation_hi, facecolor='r', alpha=0.7)
# ax0.plot(x_tip, tip_hi, 'r', linewidth=0.5, linestyle='--')
# ax0.set_title('Output membership activity')
#
# # Turn off top/right axes
# for ax in (ax0,):
#     ax.spines['top'].set_visible(False)
#     ax.spines['right'].set_visible(False)
#     ax.get_xaxis().tick_bottom()
#     ax.get_yaxis().tick_left()
#
# plt.tight_layout()
#
# """
# .. image:: PLOT2RST.current_figure
#
# Rule aggregation
# ----------------
#
# With the *activity* of each output membership function known, all output
# membership functions must be combined. This is typically done using a
# maximum operator. This step is also known as *aggregation*.
#
# Defuzzification
# ---------------
# Finally, to get a real world answer, we return to *crisp* logic from the
# world of fuzzy membership functions. For the purposes of this example
# the centroid method will be used.
#
# The result is a tip of **19.84%**.
# ---------------------------------
# """
#
# # Aggregate all three output membership functions together
# aggregated = np.fmax(tip_activation_lo,
#                      np.fmax(tip_activation_md, tip_activation_hi))
#
# # Calculate defuzzified result
# tip = fuzz.defuzz(x_tip, aggregated, 'centroid')
# tip_activation = fuzz.interp_membership(x_tip, aggregated, tip)  # for plot
#
# # Visualize this
# fig, ax0 = plt.subplots(figsize=(8, 3))
#
# ax0.plot(x_tip, tip_lo, 'b', linewidth=0.5, linestyle='--', )
# ax0.plot(x_tip, tip_md, 'g', linewidth=0.5, linestyle='--')
# ax0.plot(x_tip, tip_hi, 'r', linewidth=0.5, linestyle='--')
# ax0.fill_between(x_tip, tip0, aggregated, facecolor='Orange', alpha=0.7)
# ax0.plot([tip, tip], [0, tip_activation], 'k', linewidth=1.5, alpha=0.9)
# ax0.set_title('Aggregated membership and result (line)')
#
# # Turn off top/right axes
# for ax in (ax0,):
#     ax.spines['top'].set_visible(False)
#     ax.spines['right'].set_visible(False)
#     ax.get_xaxis().tick_bottom()
#     ax.get_yaxis().tick_left()
#
# plt.tight_layout()
#
# """
# .. image:: PLOT2RST.current_figure
#
# Final thoughts
# --------------
#
# The power of fuzzy systems is allowing complicated, intuitive behavior based
# on a sparse system of rules with minimal overhead. Note our membership
# function universes were coarse, only defined at the integers, but
# ``fuzz.interp_membership`` allowed the effective resolution to increase on
# demand. This system can respond to arbitrarily small changes in inputs,
# and the processing burden is minimal.
#
# """


"""
Implements iteration on the Bellman equations to solve the McCall growth model

"""

import numpy as np
from quantecon.distributions import BetaBinomial
from numba import jit

# A default utility function

@jit
def u(c, sigma):
    if c > 0:
        return (c**(1 - sigma) - 1) / (1 - sigma)
    else:
        return -10e6

class McCallModel:
    """
    Stores the parameters and functions associated with a given model.
    """

    def __init__(self, alpha=0.2,    # Job separation rate
                        beta=0.98,   # Discount rate
                        gamma=0.7,   # Job offer rate
                        c=6.0,       # Unemployment compensation
                        sigma=2.0,   # Utility parameter
                        w_vec=None,  # Possible wage values
                        p_vec=None): # Probabilities over w_vec

        self.alpha, self.beta, self.gamma, self.c = alpha, beta, gamma, c
        self.sigma = sigma

        # Add a default wage vector and probabilities over the vector using
        # the beta-binomial distribution
        if w_vec is None:
            n = 60  # number of possible outcomes for wage
            self.w_vec = np.linspace(10, 20, n)     # wages between 10 and 20
            a, b = 600, 400  # shape parameters
            dist = BetaBinomial(n-1, a, b)
            self.p_vec = dist.pdf()
        else:
            self.w_vec = w_vec
            self.p_vec = p_vec

@jit
def _update_bellman(alpha, beta, gamma, c, sigma, w_vec, p_vec, V, V_new, U):
    """
    A jitted function to update the Bellman equations.  Note that V_new is
    modified in place (i.e, modified by this function).  The new value of U is
    returned.

    """
    for w_idx, w in enumerate(w_vec):
        # w_idx indexes the vector of possible wages
        V_new[w_idx] = u(w, sigma) + beta * ((1 - alpha) * V[w_idx] + alpha * U)

    U_new = u(c, sigma) + beta * (1 - gamma) * U + \
                    beta * gamma * np.sum(np.maximum(U, V) * p_vec)

    return U_new

def solve_mccall_model(mcm, tol=1e-5, max_iter=2000):
    """
    Iterates to convergence on the Bellman equations

    Parameters
    ----------
    mcm : an instance of McCallModel
    tol : float
        error tolerance
    max_iter : int
        the maximum number of iterations
    """

    V = np.ones(len(mcm.w_vec))  # Initial guess of V
    V_new = np.empty_like(V)     # To store updates to V
    U = 1                        # Initial guess of U
    i = 0
    error = tol + 1

    while error > tol and i < max_iter:
        U_new = _update_bellman(mcm.alpha, mcm.beta, mcm.gamma,
                mcm.c, mcm.sigma, mcm.w_vec, mcm.p_vec, V, V_new, U)
        error_1 = np.max(np.abs(V_new - V))
        error_2 = np.abs(U_new - U)
        error = max(error_1, error_2)
        V[:] = V_new
        U = U_new
        i += 1

    return V, U


import random
import math

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

__author__ = '__Girish_Hegde__'

class Sampler:
    def __init__(self, radius=1, center=(0, 0), method='rejection_sample'):
        self.radius = radius
        self.r2 = radius**2
        self.cx, self.cy = center
        self._sample_unit_circle = getattr(self, method)

    def sample(self, n=1):
        points = []
        for i in range(n):
            x, y = self._sample_unit_circle()
            # translate (x, y)
            x, y = self.cx + x*self.radius, self.cy + y*self.radius
            points.append((x, y))
        return np.array(points)

    def rejection_sample(self):
        """Rejection Sampling

        1. point = uniform()
        2. if point satisfies required equation: return point
        3. else: repeat 1, 2, 3

        For circle:
            eqution: x2 + y2 = r2
            prob(success) = area(circle)/area(square)
                          = (pi.r2)/(4r2)
                          = pi/4 = 78.5%
            average trials per sample = 4/pi = 1.28

        """
        x = (random.random() - 0.5)*2
        y = (random.random() - 0.5)*2
        # check if (x, y) inside unit circle
        while not x*x + y*y < 1:
            # uniform(-1, 1)
            x = (random.random() - 0.5)*2
            y = (random.random() - 0.5)*2
        return (x, y)

    def ITS(self):
        """Inverse Transform Samples

        1. Get pdf
        2. cdf = integration(pdf)
        3. Get inverse cdf
        3. sample = inverse_cdf(uniform sample)

        For circle:
            polar coords -> (r, theta)
            theta = uniform(0, 2.pi)
            radius sampling:
                r != uniform(0, 1) <- as radius increases perimeter increases
                hence uniform sampling -> samples(large radius) < samples(small radius)
                -----------------------------------------------------------------------
                samples = k.perimeter = k.2.pi.r
                pdf = mr
                integral(pdf) = prob(samples space) = 1
                mr2/2 = 1
                m = 2
                pdf = 2r
                cdf = integral(pdf) = r2
                r = sqrt(uniform(0, 1)) <- inverse transform

        """
        # uniform_sample(0, 2.pi)
        theta = random.random()*2*math.pi
        # r = sqrt(uniform(0, 1)) <- inverse transform
        radius = math.sqrt(random.random())
        # polar -> cartesian
        x = radius*math.cos(theta)
        y = radius*math.sin(theta)
        return (x, y)

    def triangle_sample(self):
        """ Zero Area Triangle Sampling

        1. consider a parallellogram
        2. v1 = sample a vector along 1 side
        3. v2 = sample a vector along adjacent side
        4. point inside ||gm = v1 + v2
        5. point inside triangle = v1 + v2 if inside diagonal else reflect v1 + v2

        For circle:
            consider circle is made up of infinite triangles of area zero -> lines
            sample = uniform(0, 1) + uniform(0, 1)
            radius = sample  if sample < 1 else 2 - sample
            choose triangle -> theta = uniform(0, 2.pi)
            Note: pdf(of this method) == pdf(ITS method above) = 2r

        """
        # uniform_sample(0, 2.pi)
        theta = random.random()*2*math.pi
        radius = random.random() + random.random()
        if radius >= 1:
            radius = 2 - radius
        # polar -> cartesian
        x = radius*math.cos(theta)
        y = radius*math.sin(theta)
        return (x, y)

def main():
    r = 200
    # cx, cy = -200, 100
    cx, cy = 0, 0
    n = 10000
    clr = (0, 0, 255)

    hw = 3*(max(abs(cx), abs(cy)) + r)
    if hw%2 == 0:
        hw += 1
    coord_frame = np.zeros((hw, hw, 3),  dtype=np.uint8)
    coord_frame[hw//2, :] = 255
    coord_frame[:, hw//2] = 255
    cv2.circle(coord_frame, (hw//2  + cx, hw - (hw//2 +cy)), r, (255, 0, 0))

    sampler = Sampler(r, (cx, cy),  'ITS')
    # sampler = Sampler(r, (cx, cy),  'rejection_sample')
    # sampler = Sampler(r, (cx, cy),  'triangle_sample')

    samples = sampler.sample(n).astype(np.int32)
    for pt in  samples:
        coord_frame[hw - (hw//2 + pt[1]), hw//2 + pt[0]] = clr
        cv2.imshow("circle sampling", coord_frame)
        k = cv2.waitKey(1)
        if k == ord('q'):
            break

    # coord_frame[hw - 1 - (hw//2 + samples[:, 1]), hw//2 + samples[:, 0]] = [0, 0, 255]
    # cv2.imshow("circle sampling", coord_frame)
    # cv2.waitKey()
    # cv2.destroyAllWindows()

if __name__ == '__main__':
    main()


import numpy as np
from tf import transformations

import numpy as np

def yaw_from_pose(pose):
    quaternion = (
        pose.orientation.x,
        pose.orientation.y,
        pose.orientation.z,
        pose.orientation.w)
    euler = transformations.euler_from_quaternion(quaternion)
    yaw = euler[2]
    return yaw

def dist_of_poses(pose0, pose1):
    point_0 = np.array([
        pose0.position.x,
        pose0.position.y,
        pose0.position.z
    ])
    point_1 = np.array([
        pose1.position.x,
        pose1.position.y,
        pose1.position.z
    ])
    diff = point_0 - point_1
    return np.sqrt(np.sum(np.square(diff)))

def curvature_from_poses(pose0, pose1):
    yaw_0 = yaw_from_pose(pose0)
    yaw_1 = yaw_from_pose(pose1)
    distance = dist_of_poses(pose0, pose1)

    return (yaw_1 - yaw_0) / distance


import numpy as np
import math
import matplotlib.pyplot as plt
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei']

def loadData(fileName):
    x = [[], [], [], [], [], [], [], [], [], []]
    inFile = open(fileName, 'r')  # 以只读方式打开fileName文件
    for c in inFile.readlines():
        c_array=c.split(',')
        for i in range(10):
            x[i].append(float(c_array[i]))
    return x

a=loadData("magic04.txt")
x = np.array(a) #将原始数据化成矩阵
z = np.array(x.mean(axis=1)).reshape(10, 1) #计算原数据的均值向量（10*1）
p=x-z   #计算中心化后的矩阵
def inner():
    #使用内积计算协方差矩阵，存储在y中
    y=np.dot(x-z,(x-z).T)/19019
    return y

def outer():
    #使用外积计算协方差矩阵，最后存储在d中，为10*10矩阵
    d=np.zeros(shape=(10,10))
    for c in range(19020):
        b=p.T[c]
        d=d+np.outer(b,b)
    d=d/19019
    return d

def cosineAndCorrelation():
    v=np.dot(p[0],p[1])
    v0=np.dot(p[0],p[0])
    v1=np.dot(p[1],p[1])
    cosine=v/math.sqrt(v0*v1)
    #相关系数和标准化后的1,2属性的角度余弦值相等
    plt.scatter(x[0], x[1],s=0.1)
    plt.xlabel("第一属性")
    plt.ylabel("第二属性")
    plt.show()
    return cosine

def normfun(x0, mu, sigma):
    # normfun正态分布函数，mu: 均值，sigma:标准差，pdf:概率密度函数，np.exp():概率密度函数公式
    pdf = np.exp(-((x0 - mu)**2) / (2* sigma**2)) / (sigma * np.sqrt(2*np.pi))
    return pdf

def plotNormalDis():
    # 计算属性1的均值与标准差
    mean=np.mean(x[0])
    std=np.std(x[0])
    # x的范围为，以0.01为单位,需x根据范围调试
    a0 = np.arange(0, 335, 0.01)
    b = normfun(a0, mean, std)
    plt.plot(a0,b, color='g',linewidth = 1)
    #数据，数组，颜色，颜色深浅，组宽，显示频率
    plt.hist(x[0], bins=300,color='r',alpha=0.5,rwidth= 0.9,density=True)
    plt.xlabel("第一属性值")
    plt.ylabel("概率")
    plt.show()

def variance():
    vari=[0 for t in range(10)]
    for i in range(10):
        vari[i]=np.var(a[i])
    print("方差最大的属性是：",argmax(vari)+1,"，方差最小的属性是：",argmin(vari)+1)

def covariance():
    li=[]
    for m in range (10):
        for n in range (m+1,10):
            d=np.dot(p[m],p[n])/19019
            li.append(d)
    print("协方差最大的两组属性是：0和",argmax(li)+1,"；协方差最小的两组属性是：0和",argmin(li)+1)

def main():
    print('数据均值向量：\n',z)
    print('内积算协方差矩阵：\n',inner())
    print('外积算协方差矩阵：\n',outer())
    co=cosineAndCorrelation()
    print('属性1、2的相关性为：',co)
    plotNormalDis()
    variance()
    covariance()

if __name__ == '__main__':
    main()


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

import numpy as np

def rotate_vector(vector, rot_mat):

    "rotating a vector by a rotation matrix"
    rotated_vec = np.dot(vector,rot_mat)
    return rotated_vec

def rotation_matrix_3D(vector, theta):

    """counterclockwise rotation about a unit vector by theta radians using
    Euler-Rodrigues formula: https://en.wikipedia.org/wiki/Euler-Rodrigues_formula"""

    a=np.cos(theta/2.0)
    b,c,d=-vector*np.sin(theta/2.0)
    aa,bb,cc,dd=a**2, b**2, c**2, d**2
    bc,ad,ac,ab,bd,cd=b*c, a*d, a*c, a*b, b*d, c*d

    rot_mat=np.array([[aa+bb-cc-dd, 2*(bc+ad), 2*(bd-ac)],
                         [2*(bc-ad), aa+cc-bb-dd, 2*(cd+ab)],
                         [2*(bd+ac), 2*(cd-ab), aa+dd-bb-cc]])
    return rot_mat

def unit_normal_vector(vec1, vec2):

    n = np.cross(vec1, vec2)
    if np.array_equal(n, np.array([0, 0, 0])):
        n = vec1

    s = max(np.sqrt(np.dot(n,n)), 1e-5)
    n = n/s
    return n

def angle(vec1, vec2):

    theta=np.arccos(np.dot(vec1,vec2) / (np.sqrt(np.dot(vec1,vec1)) * np.sqrt(np.dot(vec2, vec2))))
    return theta


from math import tanh, log, log10, exp
import numpy as np

class Var:
    """
    A variable which holds a number and enables gradient computations.

    Adapted from Rasmus Berg Palm `repository <https://github.com/rasmusbergpalm/nanograd>`_.

    Parameters
    ----------
    val : float or int
        The actual value of the number.
    parents : list, optional
        List where each item has the following structure (:class:`Var`, gradient)

    Attributes
    ----------
    grad : float or int
        Partial derivative of this variable with respect to the variable from which the bakcward method was called.

    Raises
    ------
    AssertionError
        If the val is not float or int.

    """

    def __init__(self, val, parents=None):
        assert type(val) in {float, int}
        if parents is None:
            parents = []
        self.v = val
        self.parents = parents
        self.grad = 0.0

    def backprop(self, bp):
        self.grad += bp
        for parent, grad in self.parents:
            parent.backprop(grad * bp)

    def backward(self):
        """
        Compute gradient of this Var with respect to all its parents.
        """
        self.backprop(1.0)

    def __add__(self, other):
        return Var(self.v + other.v, [(self, 1.0), (other, 1.0)])

    def __mul__(self, other):
        return Var(self.v * other.v, [(self, other.v), (other, self.v)])

    def __pow__(self, power):
        assert type(power) in {float, int}, "power must be float or int"
        return Var(self.v ** power, [(self, power * self.v ** (power - 1))])

    def __neg__(self):
        return Var(-1.0) * self

    def __sub__(self, other):
        return self + (-other)

    def __truediv__(self, other):
        return self * other ** -1

    def __lt__(self, other):
        return self.v < other.v

    def tanh(self):
        """Peform Tanh activation function.
        """
        return Var(tanh(self.v), [(self, 1 - tanh(self.v) ** 2)])

    def relu(self):
        """Peform Relu activation function.

        Relu is defined as follows:

        .. math::

            relu(x) = max(0, x)

        """
        return Var(self.v if self.v > 0.0 else 0.0, [(self, 1.0 if self.v > 0.0 else 0.0)])

    def log(self):
        """Peform log function. (base 10)
        """
        return Var(log10(self.v), [(self, 1 / self.v * log(10))])

    def exp(self):
        """Peform exp function.
        """
        return Var(exp(self.v), [(self, exp(self.v))])

    def __float__(self):
        return self.v

    def __int__(self):
        return int(self.v)

    def __repr__(self):
        return f'{self.v}'


"""
ALS methode for CP decomposition
"""
import numpy as np
import tensorly as tl
import time
import copy
from src._base import svd_init_fac,err

def err_fast(norm_tensor,A,V,W):
  """
    fast data fitting error calculation of als
    Parameters
    ----------
    norm_tensor : float
        norm of the tensor
    A : matrix
        factor matrix
    V : matrix
        matrix V defined as in als
    W : matrix
        matrix W defined as in als

    Returns
    -------
    float
    data fitting error

  """
  res=sum(sum(V*(np.transpose(A).dot(A))))
  res=res-2*sum(sum(W*A))
  return(np.sqrt(norm_tensor**2+res))

def als(tensor,rank,factors=None,it_max=100,tol=1e-7,list_factors=False,error_fast=True,time_rec=False):
  """
    ALS methode of CP decomposition

    Parameters
    ----------
    tensor : tensor
    rank : int
    factors : list of matrices, optional
        an initial factor matrices. The default is None.
    it_max : int, optional
        maximal number of iteration. The default is 100.
    tol : float, optional
        error tolerance. The default is 1e-7.
    list_factors : boolean, optional
        If true, then return factor matrices of each iteration. The default is False.
    error_fast : boolean, optional
        If true, use err_fast to compute data fitting error, otherwise, use err. The default is True.
    time_rec : boolean, optional
        If true, return computation time of each iteration. The default is False.

    Returns
    -------
    the CP decomposition, number of iteration and termination criterion.
    list_fac and list_time are optional.
  """
  N=tl.ndim(tensor) # order of tensor
  norm_tensor=tl.norm(tensor) # norm of tensor
  if time_rec == True : list_time=[]
  if list_factors==True : list_fac=[] # list of factor matrices

  if (factors==None): factors=svd_init_fac(tensor,rank)

  weights=None
  it=0
  if list_factors==True : list_fac.append(copy.deepcopy(factors))
  error=[err(tensor,weights,factors)/norm_tensor]
  while (error[len(error)-1]>tol and it<it_max):
    if time_rec == True : tic=time.time()
    for n in range(N):
      V=np.ones((rank,rank))
      for i in range(len(factors)):
        if i != n : V=V*tl.dot(tl.transpose(factors[i]),factors[i])
      W=tl.cp_tensor.unfolding_dot_khatri_rao(tensor, (None,factors), n)
      factors[n]= tl.transpose(tl.solve(tl.transpose(V),tl.transpose(W)))
    if list_factors==True : list_fac.append(copy.deepcopy(factors))
    it=it+1
    if (error_fast==False) : error.append(err(tensor,weights,factors)/norm_tensor)
    else : error.append(err_fast(norm_tensor,factors[N-1],V,W)/norm_tensor)
    if time_rec == True :
      toc=time.time()
      list_time.append(toc-tic)
  # weights,factors=tl.cp_tensor.cp_normalize((None,factors))
  if list_factors==True and time_rec==True: return(weights,factors,it,error,list_fac,list_time)
  if time_rec==True : return(weights,factors,it,error,list_time)
  if list_factors==True : return(weights,factors,it,error,list_fac)
  return(weights,factors,it,error)


import numpy as np
from scipy.linalg import norm

from pdb import set_trace as st

def find_centers(X, k, seed=None):
    if not seed:
      seed = np.random.randint(10000000)
    np.random.seed(seed)
    # Initialize to K random centers
    old_centroids = random_centers(X, k)
    new_centroids = random_centers(X, k)
    while not has_converged(new_centroids, old_centroids):
        old_centroids = new_centroids
        # Assign all points in X to clusters
        clusters = cluster_points(X, old_centroids)
        # Reevaluate centers
        new_centroids = reevaluate_centers(X, clusters, k)
    return (new_centroids, clusters)

def random_centers(X, k):
    index = np.random.randint(0, X.shape[0], k)
    return X[index, :]

def has_converged(new_mu, old_mu, tol=1E-6):
    num = norm(np.array(new_mu)-np.array(old_mu))
    den = norm(new_mu)
    rel_error= num/den
    return rel_error < tol

def cluster_points(X, centroids):
    clusters = []
    for i, x in enumerate(X):
        distances = np.array([norm(x-cj) for cj in centroids])
        clusters.append( distances.argmin())
    return np.array(clusters)

def reevaluate_centers(X, clusters, k):
    centroids = []
    for j in range(k):
        cj = X[clusters==j,:].mean(axis=0)
        centroids.append(cj)
    return centroids


import numpy as np
import matplotlib.pyplot as pl
pl.style.use(['science', 'no-latex'])

def mcpi(N=1000):
    points = np.random.uniform(0,1,(2,N))
    pointsInsideIndex = np.where(np.sum(np.square(points), axis=0) <= 1)[0]
    piEstimated = pointsInsideIndex.size / N * 4.0
    return points, pointsInsideIndex, piEstimated, (piEstimated-np.pi)/np.pi

def main():
    N = 30000
    points, pointsInsideIndex, piEstimated, piError = mcpi(N)
    while (abs(piError*100.0) > 0.02):
        points, pointsInsideIndex, piEstimated, piError = mcpi(N)
    print(piEstimated)
    fig, ax = pl.subplots(figsize=[5,5], dpi=300)
    ax.set_xlim([0,1])
    ax.set_ylim([0,1])
    ax.grid()
    ax.set_title(r"Point number = %d, $\pi_e \approx$ %.4f, error = %.3f%%" %(N, piEstimated, piError*100.0), fontsize=10)
    ax.plot(points[0][pointsInsideIndex], points[1][pointsInsideIndex], 'r.', markersize=0.5)
    ax.plot(np.delete(points[0], pointsInsideIndex), np.delete(points[1], pointsInsideIndex), 'b.', markersize=0.4)
#     fig.show()
    fig.savefig("piEstimation.png", bbox_inches='tight', pad_inches=0, dpi=300)
    fig.savefig("piEstimation.pdf", bbox_inches='tight', pad_inches=0, dpi=300)
    fig.savefig("piEstimation.eps", bbox_inches='tight', pad_inches=0, dpi=300)
    pl.close()

if __name__ == "__main__":
    main()


import math
import numpy as np
from scipy import ndimage

def gauss2d(sigma, fsize):
    """
  Args:
    sigma: width of the Gaussian filter
    fsize: dimensions of the filter

  Returns:
    g: *normalized* Gaussian filter
  """

    #
    # You code here
    #

    # l2-cameras_filtering Seite 60

    m, n = fsize[0], fsize[1]
    # Just make matrixes
    x = np.arange(-m / 2 + 0.5, m / 2)
    y = np.arange(-n / 2 + 0.5, n / 2)
    # https://numpy.org/doc/stable/reference/generated/numpy.meshgrid.html
    # Expand rank
    X, Y = np.meshgrid(x, y, sparse=True)
    g = np.exp(-(X ** 2 + Y ** 2) / (2 * sigma ** 2))
    # Normalization
    return g / np.sum(g)

def createfilters():
    """
  Returns:
    fx, fy: filters as described in the problem assignment
  """

    #
    # You code here
    #

    # l3-edges_pyramids Seite 33/35
    dx = np.expand_dims(np.array([0.5, 0, -0.5]), 0)
    gy = gauss2d(0.9, [1, 3])
    fx = gy * dx
    fy = fx.T
    return fx, fy

def filterimage(I, fx, fy):
    """ Filter the image with the filters fx, fy.
  You may use the ndimage.convolve scipy-function.

  Args:
    I: a (H,W) numpy array storing image data
    fx, fy: filters

  Returns:
    Ix, Iy: images filtered by fx and fy respectively
  """

    #
    # You code here
    #
    Ix = ndimage.convolve(I, fx)
    Iy = ndimage.convolve(I, fy)
    return Ix, Iy

def detectedges(Ix, Iy, thr):
    """ Detects edges by applying a threshold on the image gradient magnitude.

  Args:
    Ix, Iy: filtered images
    thr: the threshold value

  Returns:
    edges: (H,W) array that contains the magnitude of the image gradient at edges and 0 otherwise
  """

    #
    # You code here
    #

    # l3-edges_pyramids Seite 47
    edges = np.sqrt(Ix ** 2 + Iy ** 2)
    edges[edges < thr] = 0
    return edges

def nonmaxsupp(edges, Ix, Iy):
    """ Performs non-maximum suppression on an edge map.

  Args:
    edges: edge map containing the magnitude of the image gradient at edges and 0 otherwise
    Ix, Iy: filtered images

  Returns:
    edges2: edge map where non-maximum edges are suppressed
  """

    # Store result here
    edges2 = np.ones_like(edges)

    # Expand by one pixel
    padedges = np.pad(edges, 1)

    # Edge orientation in [-90, 90]
    orientation = np.arctan(Iy / (Ix + 1e-24))

    # Store indices
    r = edges.shape[0]
    c = edges.shape[1]

    # Suppress non-maxima in 4 directions
    pi8 = math.pi / 8

    # handle top-to-bottom edges: theta in [-90, -67.5] or (67.5, 90]

    # You code here
    is_theta = np.logical_or((orientation <= -3 * pi8), (orientation > 3 * pi8))
    is_nonmax = (padedges[1:r + 1, 1:c + 1] < np.maximum(padedges[0:r, 1:c + 1], padedges[2:r + 2, 1:c + 1]))
    edges2[np.logical_and(is_theta, is_nonmax)] = 0

    # handle left-to-right edges: theta in (-22.5, 22.5]

    # You code here
    is_theta = np.logical_or((orientation > -pi8), (orientation <= pi8))
    is_nonmax = (padedges[1:r + 1, 1:c + 1] < np.maximum(padedges[1:r + 1, 0:c], padedges[1:r + 1, 2:c + 2]))
    edges2[np.logical_and(is_theta, is_nonmax)] = 0

    # handle bottomleft-to-topright edges: theta in (22.5, 67.5]

    # Your code here
    is_theta = np.logical_or((orientation > pi8), (orientation <= 3 * pi8))
    is_nonmax = (padedges[1:r + 1, 1:c + 1] < np.maximum(padedges[0:r, 0:c], padedges[2:r + 2, 2:c + 2]))
    edges2[np.logical_and(is_theta, is_nonmax)] = 0

    # handle topleft-to-bottomright edges: theta in [-67.5, -22.5]

    # Your code here
    is_theta = np.logical_or((orientation > -3 * pi8), (orientation <= -pi8))
    is_nonmax = (padedges[1:r + 1, 1:c + 1] < np.maximum(padedges[2:r + 2, 0:c], padedges[0:r, 2:c + 2]))
    edges2[np.logical_and(is_theta, is_nonmax)] = 0

    return edges2 * edges


"""
Simple Metropolis Hastings sampler taken from Hogg and Foreman-MacKey(2018):

  From Problem 2:
  Sample in a single parameter x and give the sampler
  as its density function p(x) a Gaussian density with
  mean 2 and variance 2. Make the proposal distribution
  q (x'∣x ) a Gaussian pdf for x′ with mean x and
  variance 1. Initialize the sampler with x = 0 and run
  the sampler for more than 10000 steps. Plot the results
  as a histogram with the true density overplotted sensibly.

  Redo Problem 2, but now with an input density that
  is uniform on 3<x<7 and zero everywhere else. The plot
  should look like Figure 2. What change did you have to make
  to the initialization, and why?

"""

import probayes as pb
import numpy as np
import scipy.stats
from pylab import *; ion()

n_steps = 12288

def q(**kwds):
  x, xprime = kwds['x'], kwds["x'"]
  return scipy.stats.norm.pdf(xprime, loc=x, scale=1.)

x = pb.RV('x', vtype=float, vset=(-np.inf, np.inf))
process = pb.SP(x)
process.set_prob(scipy.stats.uniform.pdf, loc=3., scale=4.,
                 order={'x': 0})
process.set_tran(q)
lambda_delta = lambda : process.Delta(x=scipy.stats.norm.rvs(loc=0., scale=1.))
process.set_delta(lambda_delta)
process.set_scores('hastings')
process.set_update('metropolis')
sampler = process.sampler({'x': 5.}, stop=n_steps)
samples = [sample for sample in sampler]
summary = process(samples)
xvals = summary.v['x']

figure()
xbins = np.linspace(np.min(xvals), np.max(xvals), 128)
xhist, _ = np.histogram(xvals, xbins)
xprop = xhist / (n_steps * (xbins[1]-xbins[0]))
step(xbins[:-1], xprop, 'b')
norm_x = scipy.stats.uniform.pdf(xbins, loc=3., scale=4.)
plot(xbins, norm_x, 'r')


import matplotlib.pyplot as plt
import numpy as np

def __rescaled_length(series, offset, scale):
    n_full = len(series)
    diffs = np.diff(series[offset::scale])
    n_rescaled = len(diffs) + 1
    sum_term = np.sum(np.abs(diffs))
    return (n_full - 1) / (n_rescaled * (scale ** 2)) * sum_term

def __mean_length(series, scale):
    return np.mean(
        [__rescaled_length(series, offset, scale) for offset in np.arange(0, scale)]
    )

def higuchi_dimension(
    series: list[float], scales: list[int], plot_curves: bool = False
):
    """Calculate Higuchi dimension.

    Args:
        series      - 1D list of real numbers, whose Higuchi dimension needs to
                      be estimated.
        scales      - 1D list of integer numbers describing the scales at which
                      the series ought to be analysed.
        plot_curves - whether to plot the length vs 1/scale plot. (optional)

    Returns:
        An estimate of Higuchi dimension. Optionally one can choose to plot
        the curves, from which the Higuchi dimension is estimated.
    """
    log_lengths = np.log([__mean_length(series, scale) for scale in scales])
    log_scales = -np.log(scales)

    coeffs = np.polyfit(log_scales, log_lengths, 1)

    if plot_curves:
        plt.figure()
        plt.xlabel("log(1/scale)")
        plt.ylabel("log(length)")
        plt.plot(log_scales, log_lengths, "ro")
        plt.plot(log_scales, np.polyval(coeffs, log_scales), "k-")
        plt.show()

    return coeffs[0]


import numpy as np
"""Shape of an Array
Shape of a two-dimensional array

The function "shape" returns the shape of an array. The shape is a tuple of integers. These numbers denote the lengths of the corresponding array dimension. In other words: The "shape" of an array is a tuple with the number of elements per axis (dimension). In our example, the shape is equal to (6, 3), i.e. we have 6 lines and 3 columns.
"""
x = np.array([ [67, 63, 87],
               [77, 69, 59],
               [85, 87, 99],
               [79, 72, 71],
               [63, 89, 93],
               [68, 92, 78]])
print(np.shape(x))


from assertpy import assert_that
import numpy
import pytest

from waves import bead_matrix
from waves import sorted_eigensystem
from waves import decompose

EPSILON = 1e-5

def normalize(v):
    norm = numpy.linalg.norm(v)
    if norm == 0:
        return v
    return v / norm

def test_bead_matrix_fail():
    with pytest.raises(ValueError):
        bead_matrix(dimension=3)

def test_bead_matrix():
    expected_matrix = numpy.array(
        [
            [-2, 1, 0, 0, 0],
            [1, -2, 1, 0, 0],
            [0, 1, -2, 1, 0],
            [0, 0, 1, -2, 1],
            [0, 0, 0, 1, -2],
        ]
    )

    flattened_expected = expected_matrix.flatten()
    flattened_actual = bead_matrix(dimension=5).flatten()
    for (a, b) in zip(flattened_actual, flattened_expected):
        assert_that(a).is_close_to(b, EPSILON)

def test_sorted_eigensystem():
    matrix = numpy.array(
        [
            [1, 1, 2],
            [-1, 3, 2],
            [-1, 2, 3],
        ]
    )

    eigenvalues, eigenvectors = sorted_eigensystem(matrix)
    expected_eigenvalues = [4, 2, 1]
    expected_eigenvectors = numpy.array([
        numpy.array([1, 1, 1]) / numpy.sqrt(3),
        numpy.array([-3, -1, -1]) / numpy.sqrt(11),
        numpy.array([-2, -2, 1]) / 3,
    ])

    for (e1, e2) in zip(eigenvalues, expected_eigenvalues):
        assert_that(e1).is_close_to(e2, EPSILON)

    for (v1, v2) in zip(eigenvectors, expected_eigenvectors):
        for (a, b) in zip(v1, v2):
            assert_that(a).is_close_to(b, EPSILON)

def test_decompose():
    eigenvectors = numpy.array(
        [
            numpy.array([1, 1, 1]) / numpy.sqrt(3),
            numpy.array([-3, -1, -1]) / numpy.sqrt(11),
            numpy.array([-2, -2, 1]) / 3,
        ]
    )

    vector = numpy.array([1, 2, 3])
    decomposition = decompose(eigenvectors, vector)

    expected_decomposition = {
        0: (1 + 2 + 3) / 3**0.5,
        1: (-3 - 2 - 3) / 11**0.5,
        2: (-2 - 4 + 3) / 3,
    }

    for key in decomposition.keys():
        assert_that(decomposition[key]).is_close_to(
            expected_decomposition[key], EPSILON)


# -*- coding: utf-8 -*-
"""
Created on Mon Nov 26 15:31:57 2018
构成比的卡方检验
Chi-square test of independence of variables in a contingency table.
@author: lenovo
"""
from scipy.stats import chi2_contingency
from scipy.stats import chi2
import numpy as np

def lc_chi2(data):
    # data=np.array([[10,20],[10,30],[20,400]])
    results = chi2_contingency(data)
    chi2value = results[0]
    pvalue = results[1]
    return (chi2value, pvalue)

def lc_chisqure(obs, tt):
    """
    obs: observed frequence
    tt: total number of each group
    NOTE. Make sure the number are np.array
    The results is in line with SPSS
    """
    tt = np.array(tt)
    obs1 = obs
    obs1 = np.array(obs1)
    obs2 = tt - obs1
    obs_all = np.vstack([obs1, obs2]).T
    n_row = np.shape(obs_all)[0]
    n_col = np.shape(obs_all)[1]
    df = (n_row - 1) * (n_col) / 2  # free degree

    frq1 = np.sum(obs1) / np.sum(tt)
    frq2 = np.sum(obs2) / np.sum(tt)
    f_exp1 = tt * frq1
    f_exp2 = tt * frq2
    f_exp = np.vstack([f_exp1, f_exp2]).T

    chisqurevalue = np.sum(((obs_all - f_exp)**2) / f_exp)
    p = (1 - chi2.cdf(chisqurevalue, df=df))
    return chisqurevalue, p

if __name__ == "__main__":
    tt = [120, 81 - 20]
    obs = [31, 67 - 20]
    print(lc_chisqure(obs, tt))


import math
import time

import torch
import numpy as np
from d2l import torch as d2l

def normal(x, mu, sigma):
    """
    the function of Normal Distribution, see ch3.1.3
    """
    p = 1 / math.sqrt(2 * math.pi * sigma ** 2)
    return p * np.exp(-0.5 / sigma ** 2 * (x - mu) ** 2)

class Timer:
    """
    Record multiple running times.
    """

    def __init__(self):
        self.times = []
        self.start()

    def start(self):
        """
        Start the timer.
        """
        self.tik = time.time()

    def stop(self):
        """
        Stop the timer and record the time in a list.
        """
        self.times.append(time.time() - self.tik)
        return self.times[-1]

    def avg(self):
        """
        Return the average time.
        """
        return sum(self.times) / len(self.times)

    def sum(self):
        """
        Return the sum of time.
        """
        return sum(self.times)

    def cumsum(self):
        """
        Return the accumulated time.
        """
        return np.array(self.times).cumsum().tolist()

if __name__ == "__main__":
    NUM = 10000
    a = torch.ones(NUM)
    b = torch.ones(NUM)
    c = torch.zeros(NUM)
    timer = Timer()
    for i in range(NUM):
        c[i] = a[i] + b[i]
    print(f"{timer.stop():.5f} sec")

    timer.start()
    d = a + b
    print(f"{timer.stop():.5f} sec")

    # Use numpy again for visualization
    x = np.arange(-7, 7, 0.01)

    # Mean and standard deviation pairs
    params = [(0, 1), (0, 2), (3, 1)]
    d2l.plot(
        x,
        [normal(x, mu, sigma) for mu, sigma in params],
        xlabel="x",
        ylabel="p(x)",
        figsize=(4.5, 2.5),
        legend=[f"mean {mu}, std {sigma}" for mu, sigma in params],
    )


"""
It was proposed by Christian Goldbach that every odd composite number can be written as the sum of a prime and twice a square.

9 = 7 + 2*1^2
15 = 7 + 2*2^2
21 = 3 + 2*3^2
25 = 7 + 2*3^2
27 = 19 + 2*2^2
33 = 31 + 2*1^2

It turns out that the conjecture was false.

What is the smallest odd composite that cannot be written as the sum of a prime and twice a square?
"""

import numpy as np

def generate_primes(n=1000):
	primes = [1]
	prime_flags = [0]*(n+1)
	for prime in xrange(2, n):
		if prime_flags[prime] == 0:
			primes.append(prime)
		else:
			continue
		mult = 2
		while mult*prime < n:
			prime_flags[mult*prime] = 1
			mult += 1
	return primes

primes = generate_primes(10000)

for i in xrange(1,10000, 2):
	print("%d: " % i),
	found = False
	for prime in primes:
		print("%d," % prime),
		if prime > i:
			break
		rez = ((i-prime)/2)**0.5
		if rez == int(rez):
			print("found %d+2*%d^2" % (prime, rez))
			found = True
			break
	if not found:
		print("\n%d couldn't be formulated as parts" % i)
		break


import numpy as np

# TODO: look for library that can represent rotation group else make one
# https: // en.wikipedia.org / wiki / Rotation_group_SO(3)

def rotate(xy, theta):
    # TODO: check shapes
    return rotation_matrix_2d(theta) @ xy

def rotate_degrees(xy, theta):
    return rotate(xy, np.radians(theta))

def rotation_matrix_2d(theta):
    """Rotation matrix"""
    cos = np.cos(theta)
    sin = np.sin(theta)
    return np.array([[cos, -sin],
                     [sin, cos]])

# aliases
rotation_matrix = rotation_matrix_2d
rotate_2d = rotate
rotate_degrees_2d = rotate_degrees

def rotation_matrix_3d(axis, theta):
    """
    Use Euler–Rodrigues formula to generate the 3x3 rotation matrix for
    rotation of `theta` radians about Cartesian direction vector `axis`.

    Any 3d rotation can be represented this way: see Euler's rotation theorem.
    These rotations have a group structure and can thus be composed to yield
    another rotation.

    see: https://en.wikipedia.org/wiki/Euler%E2%80%93Rodrigues_formula
    """

    axis = np.asarray(axis)
    axis /= np.sqrt((axis * axis).sum())

    # 'Rodriguez parameters'
    a = np.cos(theta / 2)
    b, c, d = -axis * np.sin(theta / 2)

    # Rotation matrix
    aa, ac, ad = a * (a, c, d)
    bb, bc, bd = b * (b, c, d)
    cc, cd = c * (c, d)
    dd = d * d
    return  np.array([
        [aa + bb - cc - dd, 2 * (bc - ad),     2 * (bd + ac)],
        [2 * (bc + ad),     aa + cc - bb - dd, 2 * (cd - a * b)],
        [2 * (bd - ac),     2 * (cd + a * b),  aa + dd - bb - cc]
    ])

def rotate_3d(data, axis, theta):  # TODO: rename rotate_3d
    """Rotate `data` about `axis` by `theta` radians"""
    # Cast array in shape for matrix
    # data = data.reshape(data.shape)
    # multiplication (shape will be (r,c,3,1) where X,Y,Z have shape (r,c))
    # TODO: deduce dimensionality from axis
    R = rotation_matrix_3d(axis, theta)  # 3x3 rotation matrix

    # Coordinate transform
    XR, YR, ZR = np.dot(R, data).squeeze()
    # (higher dimensional equivalent of Matrix multiplication by R on each
    # point x,y,z in X,Y,Z).  squeeze flattens singular dimensions
    return XR, YR, ZR

def rotate_degrees_3d(data, axis, theta):
    """Rotate `data` about `axis` by `theta` degrees"""
    return rotate_3d(data, axis, np.radians(theta))


"""
Functions dealing with correlation

This file is a part of BdPy.
"""

__all__ = ['corrcoef', 'corrmat']

import numpy as np
from numpy.matlib import repmat

def corrcoef(x, y, var='row'):
    """
    Returns correlation coefficients between `x` and `y`

    Parameters
    ----------
    x, y : array_like
        Matrix or vector
    var : str, 'row' or 'col'
        Specifying whether rows (default) or columns represent variables

    Returns
    -------
    r
        Correlation coefficients
    """

    # Convert vectors to arrays
    if x.ndim == 1:
        x = np.array([x])

    if y.ndim == 1:
        y = np.array([y])

    # Normalize x and y to row-var format
    if var == 'row':
        # 'rowvar=1' in np.corrcoef

        # Vertical vector --> horizontal
        if x.shape[1] == 1:
            x = x.T
        if y.shape[1] == 1:
            y = y.T
    elif var == 'col':
        # 'rowvar=0' in np.corrcoef

        # Horizontal vector --> vertical
        if x.shape[0] == 1:
            x = x.T
        if y.shape[0] == 1:
            y = y.T

        # Convert to rowvar=1
        x = x.T
        y = y.T
    else:
        raise ValueError('Unknown var parameter specified')

    # Match size of x and y
    if x.shape[0] == 1 and y.shape[0] != 1:
        x = repmat(x, y.shape[0], 1)

    elif x.shape[0] != 1 and y.shape[0] == 1:
        y = repmat(y, x.shape[0], 1)

    # Check size of normalized x and y
    if x.shape != y.shape:
        raise TypeError('Input matrixes size mismatch')

    # Get num variables
    nvar = x.shape[0]

    # Get correlation
    rmat = np.corrcoef(x, y, rowvar=1)
    r = np.diag(rmat[:nvar, nvar:])

    return r

def corrmat(x, y, var='row'):
    """
    Returns correlation matrix between `x` and `y`

    Parameters
    ----------
    x, y : array_like
        Matrix or vector
    var : str, 'row' or 'col'
        Specifying whether rows (default) or columns represent variables

    Returns
    -------
    rmat
        Correlation matrix
    """

    # Fix x and y to represent variables in each row
    if var == 'row':
        pass
    elif var == 'col':
        x = x.T
        y = y.T
    else:
        raise ValueError('Unknown var parameter specified')

    nobs = x.shape[1]

    # Subtract mean(a, axis=1) from a
    submean = lambda a: a - np.matrix(np.mean(a, axis=1)).T

    cmat = (np.dot(submean(x), submean(y).T) / (nobs - 1)) / np.dot(np.matrix(np.std(x, axis=1, ddof=1)).T, np.matrix(np.std(y, axis=1, ddof=1)))

    return np.array(cmat)


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

qe = 1.60217662e-19
me = 9.10938356e-31
B0 = 0.1

# RHS of the ODE problem, dy/dx = f(x,y)
def fun(t,y):
   vx = y[3]
   vy = y[4]
   vz = y[5]
   # Charge-to-mass ratio (q/m)
   qm = -qe/me
   # E-field [V/m]
   Ex = 0.0
   Ey = 0.0
   Ez = 0.0
   # B-field [T]
   Bx = 0.0
   By = 0.0
   Bz = B0
   # Newton-Lorentz equation (in Cartesian Coords)
   ax = qm * Ex + qm*( Bz*vy - By*vz )
   ay = qm * Ey + qm*( Bx*vz - Bz*vx )
   az = qm * Ez + qm*( By*vx - Bx*vy )
   ydot = np.array(( vx, vy, vz, ax, ay, az ))
   return ydot

def main():

   # Initial velocity [m/s]
   vy0 = 1.0e6
   # Larmor pulsation [rad/s]
   w_L = qe/me * B0
   # Larmor period [s]
   tau_L = 2.0*np.pi/w_L
   # Larmor radius [m]
   r_L = vy0/w_L

   # Initial conditions
   y0 = np.array(( r_L, 0.0, 0.0, 0.0, vy0, 0.0 ))

   # Euler Forward
   time_ef = np.linspace( 0.0, tau_L, 10 )
   y_ef = ode.euler( fun, time_ef, y0 )

   # Explicit Midpoint
   time_mp = np.linspace( 0.0, tau_L, 10 )
   y_mp = ode.midpoint( fun, time_mp, y0 )

   # Runge-Kutta 4
   time_rk = np.linspace( 0.0, tau_L, 10 )
   y_rk = ode.rk4( fun, time_rk, y0 )

   # Amplitude (orbit radius)
   r_ef = np.sqrt( y_ef[:,0]**2 + y_ef[:,1]**2 )
   r_mp = np.sqrt( y_mp[:,0]**2 + y_mp[:,1]**2 )
   r_rk = np.sqrt( y_rk[:,0]**2 + y_rk[:,1]**2 )

   # Plot 1 - Trajectory
   plt.figure(1)
   plt.plot( y_ef[:,0], y_ef[:,1], 'ro-', label='Euler-Forward (1st)' )
   plt.plot( y_mp[:,0], y_mp[:,1], 'go-', label='Explicit Mid-Point (2nd)' )
   plt.plot( y_rk[:,0], y_rk[:,1], 'bx-', label='Runge-Kutta (4th)' )
   plt.axis('equal')
   plt.xlabel('x [m]')
   plt.ylabel('y [m]')
   plt.title('One Larmor Gyration')
   plt.legend(loc=3)
   plt.savefig('ex03_ode_larmor_trajectory.png')

   # Plot 2 - Amplitude percent error
   plt.figure(2)
   plt.plot( time_ef/tau_L, ode.error_percent( r_L, r_ef), 'ro', label='Forward Euler (1st)' )
   plt.plot( time_mp/tau_L, ode.error_percent( r_L, r_mp), 'go', label='MidPoint (2nd)' )
   plt.plot( time_rk/tau_L, ode.error_percent( r_L, r_rk), 'bx', label='Runge-Kutta (4th)' )
   plt.xlabel('time / tau_Larmor')
   plt.ylabel('Percent Amplitude error [%]')
   plt.title('Percent Amplitude Error over 1 Larmor gyration ')
   plt.legend(loc=2)
   plt.savefig('ex03_ode_larmor_error.png')
   plt.show()

if __name__ == '__main__':
   main()


"""
Statistical metrics.
"""
import numpy

def union_mask(reference, predicted):
    def _get_mask(s):
        if numpy.ma.is_masked(s):
            return ~numpy.isfinite(s.filled(numpy.nan))
        return ~numpy.isfinite(s)
    return _get_mask(reference) + _get_mask(predicted)

def compute_error(reference, predicted):
    return predicted - reference

def compute_bias(reference, predicted):
    err = compute_error(reference, predicted)
    return numpy.mean(err)

def compute_rmse(reference, predicted):
    err = compute_error(reference, predicted)
    return numpy.sqrt(numpy.mean(err**2))

def compute_crmse(reference, predicted):
    err = compute_error(reference - numpy.mean(reference),
                        predicted - numpy.mean(predicted))
    return numpy.sqrt(numpy.mean(err**2))

def compute_stddev(reference):
    return numpy.std(reference, ddof=1)

def compute_corrcoef(reference, predicted):
    return numpy.corrcoef(predicted, reference)[0, 1]

def compute_mean_abs_error(reference, predicted):
    err = compute_error(reference, predicted)
    return numpy.mean(numpy.abs(err))

def compute_stat(kind, reference, predicted):
    op = {
        'bias': compute_bias,
        'rmse': compute_rmse,
        'crmse': compute_crmse,
        'stddev': compute_stddev,
        'corrcoef': compute_corrcoef,
        'mae': compute_mean_abs_error,
    }
    args = (reference, predicted)
    if kind == 'stddev':
        args = (predicted, )
    return op[kind](*args)

def _compute_all_stats(reference, predicted):
    op_list = ['bias', 'rmse', 'crmse', 'stddev', 'corrcoef', 'mae']
    return dict([(o, compute_stat(o, reference, predicted)) for o in op_list])

def compute_statistics(reference, predicted,
                       add_normalized=False, add_crmse_sign=False):

    r = numpy.copy(reference)
    p = numpy.copy(predicted)

    # keep only values that are valid in both sets
    mask = union_mask(r, p)
    r = r[~mask]
    p = p[~mask]

    ref_stats = _compute_all_stats(r, r)
    pre_stats = _compute_all_stats(r, p)

    if add_normalized:
        # Add normalized metrics in the same dict as "norm_<metric>"
        r, p = normalize_statistics(ref_stats, pre_stats,
                                    add_crmse_sign=add_crmse_sign)
        for k in r:
            ref_stats['norm_' + k] = r[k]
            pre_stats['norm_' + k] = p[k]

    return ref_stats, pre_stats

def normalize_statistics(ref_stats, pre_stats, add_crmse_sign=False):

    norm_metrics = ['bias', 'rmse', 'crmse', 'stddev', 'mae']

    def _make_norm_dict(d, scalar):
        new = dict(d)
        for key in norm_metrics:
            new[key] *= scalar
        return new

    scalar = 1.0 / ref_stats['stddev']
    nref_stats = _make_norm_dict(ref_stats, scalar)
    npre_stats = _make_norm_dict(pre_stats, scalar)

    if add_crmse_sign:
        crmse_sign = numpy.sign(pre_stats['stddev'] - ref_stats['stddev'])
        npre_stats['crmse'] *= crmse_sign

    return nref_stats, npre_stats


'''
Reference
Dabhade S A ,  Bewoor M S ,  Dabhade S A , et al. Face Recognition using Principle Component Analysis[J]. Core.kmi.open.ac.uk, 2013, ETCSIT(100):45 - 50.

> Perhaps, the simplest classification scheme is a nearest neighbor classifier in
> the image space. Under this scheme, an image in the test set is recognized
> (classified) by assigning to it the label of the closest point in the learning
> set, where distances are measured in the image space.
'''
import numpy as np

from settings import FACE_COUNT
from settings import IMAGE_COUNT_PER_FACE
from settings import TRAIN_COUNT_PER_FACE
from image_parser import read_an_image
from math_utils import get_dist

def get_center(face_num):
    center = read_an_image(face_num, 0)
    center_len = len(center)
    for i in range(1, TRAIN_COUNT_PER_FACE):
        im_i = read_an_image(face_num, i)
        assert center_len == len(im_i)
        for j in range(center_len):
            center[j] = (center[j]*i+im_i[j])/(i+1)
    return center

def get_centers():
    centers = [get_center(0)]
    for i in range(1, FACE_COUNT):
        centers = np.append(centers, [get_center(i)], axis=0)
    return centers

def recognize_face(face_num, image_num_of_this_face, centers):
    im = read_an_image(face_num, image_num_of_this_face)
    face_recognized = face_num
    key_dist = get_dist(im, centers[face_num])
    for i in range(FACE_COUNT):
        if i == face_num:
            continue
        dist = get_dist(im, centers[i])
        if dist < key_dist:
            face_recognized = i
    return face_recognized

if __name__ == '__main__':
    print('###### Minimum Distance Face Recognition ######')
    print('The face recognition results of each person are listed in the following format:')
    print('Face Number | Image Number | Face Recognized | Right or Wrong (T/F)\n...\nError Rate\n')
    centers = get_centers()
    error_count = 0
    for i in range(FACE_COUNT):
        error_count_i = 0
        for j in range(TRAIN_COUNT_PER_FACE, IMAGE_COUNT_PER_FACE):
            face_recognized = recognize_face(i, j, centers)
            t_or_f = 'T'
            if face_recognized != i:
                t_or_f = 'F'
                error_count_i += 1
            print(f'{i+1}\t{j+1}\t{face_recognized+1}\t{t_or_f}')
        error_count += error_count_i
        print(f'{error_count_i} / {IMAGE_COUNT_PER_FACE-TRAIN_COUNT_PER_FACE} = {error_count_i/(IMAGE_COUNT_PER_FACE-TRAIN_COUNT_PER_FACE)}\n')
    print('Total Error Rate:')
    print(f'{error_count} / {(IMAGE_COUNT_PER_FACE-TRAIN_COUNT_PER_FACE)*FACE_COUNT} = {error_count/((IMAGE_COUNT_PER_FACE-TRAIN_COUNT_PER_FACE)*FACE_COUNT)}')


# Copyright 2017 Battelle Energy Alliance, LLC
#
# 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.
# takes input parameters x,y
# returns value in "ans"
# elliptic paraboloid function with a single global minimum
# optimal minimum at f(-0.5, 0.5) = 0
# parameter range is -2 <= x <= 2, -2 <= y <= 2
import numpy as np

def run(raven, Inputs):
  """
    External model to evaluates 10*(x+0.5)**2 + 10*(y-0.5)**2.
    @ In, raven, object, container from RAVEN to store members on
    @ In, Input, dict, dictionary containing inputs from RAVEN
    @ Out, None
  """
  x = raven.x
  y = raven.y
  raven.ans = main(x, y)

def main(x, y):
  z = 10*(x+0.5)**2 + 10*(y-0.5)**2
  return z


import numpy as np
import quantecon as qe
import scipy.linalg as la

## Parameters

class ConsumptionProblem:
    """
    The data for a consumption problem, including some default values.
    """

    def __init__(self,
                 beta = .96,
                 y = [2, 1.5],
                 b0 = 3,
                 P = np.asarray([[.8, .2],
                                 [.4, .6]])):
        """

        Parameters
        ----------

        beta : discount factor
        P    : 2x2 transition matrix
        y    : list containing the two income levels
        b0   : debt in period 0 (= state_1 debt level)

        """
        self.beta = beta
        self.y = y
        self.b0 = b0
        self.P = P

def consumption_complete(cp):
    """
    Computes endogenous values for the complete market case.

    Parameters
    ----------

    cp : instance of ConsumptionProblem

    Returns
    -------

        c_bar : constant consumption
        b1    : rolled over b0
        b2    : debt in state_2

    associated with the price system

        Q = beta * P

    """
    beta, P, y, b0 = cp.beta, cp.P, cp.y, cp.b0  # Unpack

    y1, y2 = y          # extract income levels
    b1 = b0             # b1 is known to be equal to b0
    Q = beta * P        # assumed price system

    # Using equation (7) calculate b2
    b2 = (y2 - y1 - (Q[0, 0] - Q[1, 0] - 1) * b1)/(Q[0, 1] + 1 - Q[1, 1])

    # Using equation (5) calculae c_bar
    c_bar = y1 - b0 + Q[0, :] @ np.asarray([b1, b2])

    return c_bar, b1, b2

def consumption_incomplete(cp, N_simul=150):
    """
    Computes endogenous values for the incomplete market case.

    Parameters
    ----------

    cp : instance of ConsumptionProblem
    N_simul : int

    """

    beta, P, y, b0 = cp.beta, cp.P, cp.y, cp.b0  # Unpack
    # For the simulation define a quantecon MC class
    mc = qe.MarkovChain(P)

    # Useful variables
    y = np.asarray(y).reshape(2, 1)
    v = np.linalg.inv(np.eye(2) - beta * P) @ y

    # Simulat state path
    s_path = mc.simulate(N_simul, init = 0)

    # Store consumption and debt path
    b_path, c_path = np.ones(N_simul + 1), np.ones(N_simul)
    b_path[0] = b0

    # Optimal decisions from (12) and (13)
    db = ((1 - beta) * v - y) / beta

    for i, s in enumerate(s_path):
        c_path[i] = (1 - beta) * (v - b_path[i] * np.ones((2, 1)))[s, 0]
        b_path[i + 1] = b_path[i] + db[s, 0]

    return c_path, b_path[:-1], y[s_path], s_path


"""
Unit and regression test for the geometry_analysis package.
"""

# Import package, test suite, and other packages as needed
import geometry_analysis
import pytest
import sys

import numpy as np

def test_geometry_analysis_imported():
    """Sample test, will always pass so long as import statement worked"""
    assert "geometry_analysis" in sys.modules

def test_calculate_distance():
    """Test the calculate_distance function"""

    r1 = np.array([0, 0, -1])
    r2 = np.array([0, 1, 0])

    expected_distance = np.sqrt(2.)

    calculated_distance = geometry_analysis.calculate_distance(r1, r2)

    assert expected_distance == calculated_distance

    def test_calculate_angle_90():
        """Test the calculate_angle funciton"""


# -*- coding: utf-8 -*-
"""
Created on Sun Oct 21 09:21:04 2018

@author: Mohammad Doosti Lakhani
"""

# import libraries
import numpy as np
import matplotlib.pyplot as plt
from copy import deepcopy

def generate_sample_data(n_clusters, center_coordinates, random_data_shape):

    # the coordinate of new random data
    # we will build random data around this centers
    cc = np.zeros(shape = (n_clusters,2))
    for i in range(len(cc)):
        cc[i] = np.array(center_coordinates[i])

    # data points to cluster
    data = np.zeros(shape=(n_clusters, random_data_shape[0],random_data_shape[1]))

    for i in range(len(cc)):
        data[i] = np.random.randn(*random_data_shape) + cc[i]

    data = data.reshape((n_clusters*random_data_shape[0], random_data_shape[1]))
    return data

def plotter(data, centers = []):
    # only work for 2 dimensional data
    plot = plt.scatter(data[:,0], data[:,1], s = 4)
    if len(centers) != 0:
        plot = plt.scatter(centers[:,0], centers[:,1], marker='d', c='red', s=70)
    return plot

def fit(data, n_clusters, max_iterations = 300, threshold = 1e-10):
    m = data.shape[0] # number of training data
    n = data.shape[1] # number of features of every single train data

    # we generate random centers
    # we use standard deviation and mean to ensure centers cover all data and distributed normally
    mean = np.mean(data, axis = 0) # mean of each feature
    sigma = np.std(data, axis = 0) # standard deviation of each feature

    # randomly selected centers
    centers = np.random.randn(n_clusters,n)*sigma + mean

    old_centers = np.zeros(centers.shape) # save old centers to capture error in every update
    new_centers = deepcopy(centers) # update each time with new mean and std
    distances = np.zeros((m,n_clusters)) # distances of each point to the all centeres

    e = np.linalg.norm(new_centers - old_centers) # metric function = sqrt(sum((a-b)**2))
    threshold = 1e-10 # when we updating centers, if error was less than this, we finish our job

    while  max_iterations > 0 and e > threshold:
        for i in range(n_clusters):
            # measure distance to each center
            distances[:,i] = np.linalg.norm(data - centers[i], axis = 1)

        # assign clusters to the closest center
        clusters = np.argmin(distances, axis = 1)
        old_centers = deepcopy(new_centers)

        # update centers
        for i in range(n_clusters):
            new_centers[i] = np.mean(data[clusters == i], axis = 0)

        e = np.linalg.norm(new_centers - old_centers)
        max_iterations -= max_iterations-1

    return new_centers

d = generate_sample_data(2, [[5,7],[7,4],[3,1]], (1000,2))
c = fit(d, 2)
p = plotter(d,c)
p


from scipy.linalg import solve
import cv2 as cv
import numpy as np
# pts1: np.array, pts2: np.array
def FindFundamentalMat(pts1: np.array, pts2: np.array):
    equations = []

    for i in range(pts1.shape[1]):
        u1 = pts1[0][i]
        v1 = pts1[1][i]
        u2 = pts2[0][i]
        v2 = pts2[1][i]
        equations.append([u1*u2, v1*u2, u2, u1*v2, v1*v2, v2, u1, v1, 1])

    equations = np.array(equations).T
    U,E,V = np.linalg.svd(equations)
    f = U[:, -1]
    print(np.round(np.matmul(f, equations), 3))
    F = f.reshape(3,3)

    U,E,V_T = np.linalg.svd(F, full_matrices=False)
    indx_min_sing_val = np.argmin(E)
    E[indx_min_sing_val] = 0.
    F_sing = np.round(np.matmul(np.matmul(U,np.diag(E)), V_T), 3)
    return F_sing

def findFundamnentalMatrix(points_list):
  A = []
  for points in points_list:
    x, y = points[0]
    u, v = points[1]
    A.append([u*x, u*y, u, x*v, y*v, v, x, y, 1])

  A = np.asarray(A, dtype=np.float)
  A = A.T

  u, s, vt =  np.linalg.svd(A)
  print("Minimal Singular Value: {}\n".format(s[-1]))
  x_arr = u[:, -1]
  h_i = np.reshape(x_arr, (3,3))
  print("Fundamental matrix:\n{}\n".format(h_i))
  test = x_arr.dot(A)
  test[test < 1e-10] = 0
  print("The next values must be ZERO: {}\n\n".format(test))
  return h_i

def GeneratePts(max_coord=30, num_points=8):
    R1 = np.identity(3)
    T1 = np.zeros(3).T.reshape(3,1)
    R2 = np.identity(3)
    T2 = np.array([10,0,0]).T.reshape(3,1)

    P1 = np.append(R1, T1, axis=1)
    P2 = np.append(R2, T2, axis=1)
    Q = np.append(np.array([np.random.rand(3)*10 for j in range(num_points)]),
                  np.ones(num_points).reshape(num_points,1), axis = 1)

    q1 = np.matmul(P1, Q.T)
    q2 = np.matmul(P2, Q.T)

    return q1/q1[2], q2/q2[2]

def main():
    pts = GeneratePts()
    print(FindFundamentalMat(pts[0], pts[1]))
main()


import numpy as np

def get_angle(v1, v2):
    '''
    Get angle from 2 vectors
    '''
    return np.arccos(np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)))

def get_point_on_circle(angle, circle):
    x = circle.origin[0] + (circle.radius * np.cos(angle))
    y = circle.origin[1] + (circle.radius * np.sin(angle))
    return np.array([x, y])

def get_closest_point_on_circle(p, circle):
    '''
    Finding the closest x,y coordinates on circle, based on given point
    '''
    x_vec = np.array([1, 0])
    v = p - circle.origin
    angle = get_angle(v, x_vec)
    angle = angle if v[1] > 0 else -angle
    return get_point_on_circle(angle, circle)

if __name__ == '__main__':
    from pyrieef.geometry.workspace import Circle
    circle = Circle(origin=np.zeros(2), radius=1.0)
    p = np.array([0, 2])
    print(get_closest_point_on_circle(p, circle))
    p = np.array([-1, 1])
    print(get_closest_point_on_circle(p, circle))
    p = np.array([-1, 0])
    print(get_closest_point_on_circle(p, circle))
    p = np.array([0, -1])
    print(get_closest_point_on_circle(p, circle))
    p = np.array([1, -1])
    print(get_closest_point_on_circle(p, circle))
    p = np.array([1, 0])
    print(get_closest_point_on_circle(p, circle))


from math import gcd

from sage.all import GF
from sage.all import is_prime_power

def attack(y, m=None, a=None, c=None):
    """
    Recovers the parameters from a linear congruential generator.
    If no modulus is provided, attempts to recover the modulus from the outputs (may require many outputs).
    If no multiplier is provided, attempts to recover the multiplier from the outputs (requires at least 3 outputs).
    If no increment is provided, attempts to recover the increment from the outputs (requires at least 2 outputs).
    :param y: the sequential output values obtained from the LCG
    :param m: the modulus of the LCG (can be None)
    :param a: the multiplier of the LCG (can be None)
    :param c: the increment of the LCG (can be None)
    :return: a tuple containing the modulus, multiplier, and the increment
    """
    if m is None:
        assert len(y) >= 4, "At least 4 outputs are required to recover the modulus"
        for i in range(len(y) - 3):
            d0 = y[i + 1] - y[i]
            d1 = y[i + 2] - y[i + 1]
            d2 = y[i + 3] - y[i + 2]
            g = d2 * d0 - d1 * d1
            m = g if m is None else gcd(g, m)

        assert is_prime_power(m), "Modulus must be a prime power, try providing more outputs"

    gf = GF(m)
    if a is None:
        assert len(y) >= 3, "At least 3 outputs are required to recover the multiplier"
        x0 = gf(y[0])
        x1 = gf(y[1])
        x2 = gf(y[2])
        a = int((x2 - x1) / (x1 - x0))

    if c is None:
        assert len(y) >= 2, "At least 2 outputs are required to recover the multiplier"
        x0 = gf(y[0])
        x1 = gf(y[1])
        c = int(x1 - a * x0)

    return m, a, c


"""
This module implements
"""
import numpy as np

# TODO: implement, add descriptions etc
def haversine(start_lat,
          start_lon,
          end_lat,
          end_lon):
    """
        Calculate the great circle distance between two points
        on the earth (specified in decimal degrees).
        Computes distance in kms

            Parameters
        ----------
        start_lat: description
        start_lon: description

        Returns
        -------
        description
    """
    lat_1_rad, lon_1_rad = np.radians(start_lat), np.radians(start_lon)
    lat_2_rad, lon_2_rad = np.radians(end_lat), np.radians(end_lon)
    dlon = lon_2_rad - lon_1_rad
    dlat = lat_2_rad - lat_1_rad

    a = np.sin(dlat / 2.0) ** 2 + np.cos(lat_1_rad) * np.cos(lat_2_rad) * np.sin(dlon / 2.0) ** 2
    c = 2 * np.arcsin(np.sqrt(a))
    haversine_distance = 6371 * c

    return haversine_distance


# coding: utf-8

# In[1]:

from sklearn.datasets import load_boston
from sklearn.cross_validation import train_test_split
from sklearn import linear_model
from sklearn.metrics import mean_squared_error
import numpy as np
import random

boston = load_boston()
boston_train_X, boston_test_X, boston_train_Y, boston_test_Y = train_test_split(boston.data, boston.target, train_size=.75)
boston_train_X_main, boston_train_X_validation, boston_train_Y_main, boston_train_Y_validation = train_test_split(boston_train_X, boston_train_Y, train_size=.75)

def regression_model_validation(regr_model_id, isdefault, alpha_val):

    if regr_model_id == 0:

        if isdefault == True:

            regr_model = linear_model.Lasso()

        else:

            regr_model = linear_model.Lasso(alpha = alpha_val)

    elif regr_model_id == 1:

        if isdefault == True:

            regr_model = linear_model.Ridge()

        else:

            regr_model = linear_model.Ridge(alpha = alpha_val)

    regr_model.fit(boston_train_X_main, boston_train_Y_main)

    regr_model_predict = regr_model.predict(boston_train_X_validation)

    mean_squared_error_value = mean_squared_error(boston_train_Y_validation, regr_model_predict)

    if regr_model_id == 0:

        if isdefault == True:

            print("Lasso","alpha(Default):", mean_squared_error_value)

        else:

            print("Lasso","alpha =", alpha_val, " :", mean_squared_error_value)

    elif regr_model_id == 1:

        if isdefault == True:

            print("Ridge","alpha(Default):", mean_squared_error_value)

        else:

            print("Ridge","alpha =",alpha_val," :", mean_squared_error_value)

def lassodefault():

    regr_lasso_default = linear_model.Lasso()
    regr_lasso_default.fit(boston_train_X, boston_train_Y)
    regr_predict_lasso_default = regr_lasso_default.predict(boston_test_X)

    mean_squared_error_lasso_default = mean_squared_error(boston_test_Y, regr_predict_lasso_default)

    print("Lasso","alpha(Default):", mean_squared_error_lasso_default)

def ridgedefault():

    regr_ridge_default = linear_model.Ridge()
    regr_ridge_default.fit(boston_train_X, boston_train_Y)
    regr_predict_ridge_default = regr_ridge_default.predict(boston_test_X)

    mean_squared_error_ridge_default = mean_squared_error(boston_test_Y, regr_predict_ridge_default)

    print("ridge","alpha(Default):", mean_squared_error_ridge_default)

def regression_test_tuned(regr_model_id, alpha_val):

    if regr_model_id == 0:

        regr_model = linear_model.Lasso(alpha = alpha_val)

    elif regr_model_id == 1:

        regr_model = linear_model.Ridge(alpha = alpha_val)

    regr_model.fit(boston_train_X, boston_train_Y)

    regr_model_predict_test = regr_model.predict(boston_test_X)

    mean_squared_error_value_test = mean_squared_error(boston_test_Y, regr_model_predict_test)

    if regr_model_id == 0:

        print("Lasso","alpha =", alpha_val, " :", mean_squared_error_value_test)

    elif regr_model_id == 1:

        print("Ridge","alpha =",alpha_val," :", mean_squared_error_value_test)

print("----------------------------------------------------------------------------------------------------------------")
print("                                  Mean Squared Error(Validation)")
print("----------------------------------------------Lasso---------------------------------------------------------------")

regression_model_validation(0, True, -1)
regression_model_validation(0, False, 0.005)
regression_model_validation(0, False, 0.105)
regression_model_validation(0, False, 0.305)
regression_model_validation(0, False, 0.405)
regression_model_validation(0, False, 0.000305)
print("---------------------------------------------Ridge---------------------------------------------------------------")
regression_model_validation(1, True, -1)
regression_model_validation(1, False, 0.056)
regression_model_validation(1, False, 0.03)
regression_model_validation(1, False, 0.8883)
regression_model_validation(1, False, 0.89029)
regression_model_validation(1, False, 0.9029)
print("-----------------------------------------------------------------------------------------------------------------")
print("-----------------------------------------------------------------------------------------------------------------")
print("--------------------------------------Mean Square Error Test(Lasso params tuned)------------------------------------")

lassodefault()
print("------------------------------------------------------")
regression_test_tuned(0, 0.005)
regression_test_tuned(0, 0.105)
regression_test_tuned(0, 0.405)
regression_test_tuned(0, 0.000305)
print("--------------------------------------Mean Square Error Test(Ridge params tuned)---------------------------------------")
ridgedefault()
print("------------------------------------------------------")
regression_test_tuned(1, 0.056)
regression_test_tuned(1, 0.03)
regression_test_tuned(1, 0.883)
regression_test_tuned(1, 0.9029)


import numpy as np
from scipy import linalg as la

class MarkovChain:

    def __init__(self, pi):
        if not np.allclose(np.sum(pi, axis=1), np.ones(pi.shape[0])):
            raise ValueError('Each row of the input matrix must sum to one.')
        self.Pi = pi

    def n_steps_transition(self, n):
        return la.matrix_power(self.Pi, n)

    @property
    def stationary_distribution(self):
        l, v = la.eig(self.Pi)
        vector = v[:, np.where(np.isclose(l, 1.))]
        return vector / np.sum(vector)

    def simulate(self, T, s0):
        """
        It simulates a Markov Chain for T periods given that the initial
        state is 's'. The parameter 's0' must be an integer between 0 and
        Pi.shape[0]-1
        """
        if T < 1:
            raise ValueError('The sample length T must be at least 1.')
        if not isinstance(s0, int):
            raise TypeError('Initial condition must be an index (integer).')
        if s0 < 0 or s0 > self.Pi.shape[0] - 1:
            raise ValueError('Initial condition must be a row index of Pi.')

        def draw_state(pdf):
            cdf = np.cumsum(pdf)
            u = np.random.uniform()
            return np.sum(u - cdf > 0)

        sample = np.zeros((T,), dtype=int)
        sample[0] = s0
        for t in range(1, T):
            sample[t] = draw_state(self.Pi[sample[t - 1], :])

        return sample


import numpy

def multivariate_gaussian(x_array, mean_mu, corr_sigma):
    """
    Computes the probability density function of the multivariate gaussian distribution.

    Parameters
    ----------
    x_array : array_like
        The dataset of shape (m x n). Where there are m examples of n-dimensions.

    mean_mu : array_like
        A vector of shape (n,) contains the means for each dimension (feature).

    corr_sigma : array_like
        Either a vector of shape (n,) containing the variances of independent features
        (i.e. it is the diagonal of the correlation matrix), or the full
        correlation matrix of shape (n x n) which can represent dependent features.

    Returns
    ------
    p : array_like
        A vector of shape (m,) which contains the computed probabilities at each of the
        provided examples.
    """
    k = mean_mu.size

    # if sigma is given as a diagonal, compute the matrix
    if corr_sigma.ndim == 1:
        corr_sigma = numpy.diag(corr_sigma)

    x_array = x_array - mean_mu
    factor = (2*numpy.pi)**(-k/2)*numpy.linalg.det(corr_sigma)**(-0.5)
    exp_part = numpy.exp(-0.5*numpy.sum(numpy.dot(x_array, numpy.linalg.pinv(corr_sigma))*x_array, axis=1))

    probabilities = factor*exp_part

    return probabilities


import matplotlib.pyplot as plt
import numpy as np

def f(x):
    return x**3-3*x+1

x = np.linspace(-3,3,100)
plt.axhline(0, c='red')
plt.plot(x, f(x))
plt.show()

from scipy.optimize import brentq, newton
print(brentq(f, -3, 0), brentq(f, 0, 1), brentq(f, 1,3))
print(newton(f, -3), newton(f, 0), newton(f, 3))

fprime = lambda x: 3*x**2 - 3
print(newton(f, -3, fprime), newton(f, 0, fprime), newton(f, 3, fprime))

from sympy import symbols, N, real_roots


def pi_approx(n):
    """This function approximates pi.
    User inputs a number of points to choose
    from the space [-1, 1] x [-1, 1] and the
    function counts the number of times that
    the points fall inside the unit circle."""

    import numpy as np
    X = np.linspace(-1, 1, 100000)
    Y = X
    ctr = 0
    for _ in range(n):
        X_r = np.random.choice(X)
        Y_r = np.random.choice(Y)
        if X_r ** 2 + Y_r ** 2 <= 1:
            ctr += 1
    return 4 * ctr / n


import numpy as np

def softmax(a):
    e = np.exp(a)
    return e / e.sum(axis=1)[:, np.newaxis]

def sigmoid(a):
    return np.ones_like(a) / (np.ones_like(a) + np.exp(-a))

def d_sigmoid(a):
    return sigmoid(a) * (np.ones_like(a) - sigmoid(a))

def relu(a):
    return np.maximum(0, a)

class DifferentiableFunction(object):
    def __call__(self, x):
        raise NotImplementedError()
    def d(self, x):
        raise NotImplementedError()

class Sigmoid(DifferentiableFunction):
    def __call__(self, x):
        return sigmoid(x)
    def d(self, x):
        return d_sigmoid(x)

class Softmax(DifferentiableFunction):
    def __call__(self, x):
        return softmax(x)
    def d(self, x):
       return softmax(x) * (np.ones_like(x) - softmax(x))

class ReLu(DifferentiableFunction):
    def __call__(self, x):
        return relu(x)
    def d(self, x):
        return (x > 0).astype(np.float32)


import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from scipy.integrate import RK45

# 3 time animated subplots will be saved when the code is run, they show:
# subplot 1: phase space; the contours corresponds to possible trajectories
# the trajectory depends on the initial conditions
# subplot 2: pendulum evolution in xy space
# subplot 3: energy evolution as a function of time

# solve the equations with forward Euler and dt=0.01 and dt=0.1
# what do you notice? is this expected behavior?

# implement a leapfrog algorithm. use dt=0.1. What changes?

# is leapfrog "better" or "worse" than Forward Euler? Why?

# implement a Verlet algorithm. How do energy evolution compare with leapfrog?

# what is the difference between leapfrog and Verlet in this case?

# Does Verlet algorithm conserve energy better than Leapfrog algorithm?

# Can you compare them in terms of computational cost?

# What do you have to keep into account for leapfrog/Verlet algorithm
# when calculating the energy?

# Now solve the equation numerically use the trapezoidal integration method:
# what is the energy evolution?

# The derived Runge-Kutta method is already implemented.
# Does RK4 conserve energy over time?

'Hamiltonian of the pendulum system'
def hamiltonian(phi, p):
    return 0.5*np.multiply(p,p) + 1. - np.cos(phi)

'X & Y coordinate of the pendulum'
def beam(phi):
    x = np.sin(phi)
    y = -np.cos(phi)
    return x, y

'functions to be used in Newton-Raphson method'
def f(dt, phi, p, new_value):
    return 2./dt*new_value + dt/2.*np.sin(new_value)-2./dt

def f_prime(dt, new_value):
    return

'Newton-Raphson method for solving pendulum position'
def Pendulum_eqn(dt, phi, p):
    delta = 1e-16
    new_value = 0.75
    iterations = 0
    for i in range(100):
        residual = 0.0 # What is the right expression for residual?

        if (abs(residual) < delta):
            iterations = i
            break

        "Newton - Raphson method"

    if (iterations == 0):
        print("Solution did not converge! Residue at: ", residual)
    return new_value, residual, iterations

"Timesteps"
dt = 0.01 # 0.01, 0.1
t_end = 20
n_step = int(t_end/dt)

"Initial Conditions"
phi_0=0
p_0=1.2

"Initial time and energy"
t = np.zeros(1)

"We can switch between methods here."
ODE_method = 'Verlet' # 'Forward', 'Leapfrog', 'Verlet', 'Integration', 'RK4'

if (ODE_method == 'Verlet'):
    "Initial condition for Verlet algorithm"
    # needs velocity info at time -1/2
    p = p_0 - dt/2. * np.sin(phi_0)
    phi= phi_0

elif (ODE_method == 'Leapfrog'):
    "Initial condition for Leapfrog algorithm"
    # needs spatial coordinate info at time 1/2
    phi = phi_0 + dt/2. * p_0
    p= p_0

else:
    phi=phi_0
    p=p_0

phi_v = [phi]
p_v = [p]

hist_x = []
hist_y = []
hist_phi = []
hist_p = []
for iters in range(n_step):
    if (ODE_method == 'Forward'):
        "Forward Euler"
        phi_new = phi + dt*p
        p_new = p - dt*np.sin(phi)

    elif (ODE_method == 'Leapfrog'):
        '''
        Leapfrog algorithm
        Since the phi value is already offset by half a step in the initial condition,
        the update to p_new and phi_new is ALMOST similar to Forward Euler.
        '''
        p_new = p - dt * np.sin(phi)
        phi_new = phi + dt* p_new

    elif (ODE_method == 'Verlet'):
        '''
        Verlet algorithm
        Since the p value is already offset by half a step in the initial condition,
        the update to p_new and phi_new is ALMOST similar to Forward Euler.
        '''
        p_new = p - dt * np.sin(phi)
        phi_new = phi + dt* p_new

    elif (ODE_method == 'Integration'):
        '''
        Integration method
        First, compute either phi_new or p_new using Newton-Raphson method.
        Highly recommend to solve for phi_new, since it is a much simpler expression.
        '''
        new_value, res, its = Pendulum_eqn(dt, phi, p)
        p_new = 0.0
        phi_new = 0.0

    elif (ODE_method == 'RK4'):
        '''
        Runge-Kutta 4th order method
        You must realise that phi is a function of p & t. phi = phi(t, p)
        Also understand that p is a function of phi & t. p = p(t, phi)
        Follow your derived steps to calculate phi_new!
        '''
        p1 = p
        phi1 = phi
        k1 = p1*dt

        p2 = p1 - np.sin(phi1 + k1*0.5)*dt*0.5
        k2 = p2*dt

        p3 = p1 - np.sin(phi1 + k2*0.5)*dt*0.5
        k3 = p3*dt

        p4 = p1 - np.sin(phi1 + k3)*dt
        k4 = p4*dt

        phi_new = phi + (k1 + 2.*k2 + 2.*k3 + k4)/6.

        'Next, calculate p_new'
        f1 = -np.sin(phi1)*dt
        phi2 = phi1 + (p1 + f1*0.5)*dt*0.5

        f2 = -np.sin(phi2)*dt
        phi3 = phi1 + (p1 + f2*0.5)*dt*0.5

        f3 = -np.sin(phi3)*dt
        phi4 = phi1 + dt*(p1 + f3)

        f4 = -np.sin(phi4)*dt

        p_new = p + (f1 + 2.*f2 + 2.*f3 + f4)/6.

    else:
        print('Invalid method chosen.')

    "Update the phi & p values"
    p_v.append(p_new)
    phi_v.append(phi_new)

    phi = phi_new
    p = p_new

    "Record and extend t "
    t = np.append(t, (iters+1)*dt)

    "Limit phi to range of [-4, 4]"
    if (phi > 4): phi = phi - 2.0*np.pi
    if (phi < -4): phi = phi + 2.0*np.pi

    x, y = beam(phi)

    hist_x.append(x)
    hist_y.append(y)
    hist_phi.append(phi)
    hist_p.append(p)

if ODE_method== 'Leapfrog':
    ## the spatial coordinate calculated in leapfrog is advanced of
    # hald a timestep w.r.t. momentum
    ## this is the ``real" time at which our phi are evaluated
    t_phi= t+ 1/2.*dt
    ## now interpolate to t
    phi_v= np.interp(t, t_phi, phi_v)
    # setting phi_0, since this cannot be calculated form interpolation
    phi_v[0]= phi_0

elif ODE_method== 'Verlet':
    ## the momentum calculated in Verlet is retarded of
    # hald a timestep w.r.t. spatial coordinate

    # calculating the last value of the moentum
    p_last= p_v[-1]- np.sin(phi_v[-1])*dt/2

    ## this is the ``real" time at which our phi are evaluated
    t_p= t- 1/2.*dt
    ## now interpolate to t
    p_v= np.interp(t, t_p, p_v)
    # fixing the last point, that cannot be calculated by interpolation
    p_v[-1]= p_last

"calculate energy"
E= hamiltonian(phi_v, p_v)

if ODE_method=='Leapfrog' or ODE_method=='Verlet' or ODE_method=='Integration':
    print('Method: ', ODE_method, 'DE=' , max(E)- min(E))

"Plotting related codes: "
"Phi & p phase space contour"
phi_contour, p_contour = np.meshgrid(np.linspace(-1.5*np.pi, 1.5*np.pi, 100), \
                                      np.linspace(-2.5, 2.5, 50))

h = hamiltonian(phi_contour, p_contour)

fig = plt.figure(constrained_layout=False)
fig.set_size_inches(9, 6)#(18.5, 9.0)
gs = fig.add_gridspec(ncols=2, nrows=2)

"preparing subplot for phase space contour plot"
ax = fig.add_subplot(gs[0, 0])
ax.contourf(phi_contour, p_contour, h)
ax.set_aspect('equal')
ax.set_xlabel('phi')
ax.set_ylabel('p')

"preparing subplot for pendulum position plot"
ax1 = fig.add_subplot(gs[0, 1])
ax1.set_ylim(-1.5, 1.5)
ax1.set_xlim(-1.5, 1.5)
ax1.set_aspect('equal')
ax1.set_xlabel('x')
ax1.set_ylabel('y')

"preparing subplot for energy over time plot"
ax2 = fig.add_subplot(gs[1, 0])
ax2.set_xlim(min(t), max(t))
ax2.set_ylim(min(E), max(E))
ax2.grid()
ax2.set_xlabel('t')
ax2.set_ylabel('E')

point, = ax.plot([phi_0], [p_0], 'or')
line, = ax1.plot([], [], 'o-', lw=2)
E_graph, = ax2.plot([], [])

"function to set compute data into animation frames"
def animate(i):
    t_list = t[:i]
    E_list = E[:i]
    thisx = [0, hist_x[i]]
    thisy = [0, hist_y[i]]

    point.set_data(hist_phi[i],hist_p[i])
    line.set_data(thisx, thisy)
    E_graph.set_data(t_list, E_list)
    return point, line, E_graph,

ani = animation.FuncAnimation(
    fig, animate, len(hist_y), interval=dt*1000, blit=True)

# ani.save('Pendulum_swing.mp4', fps=30, extra_args=['-vcodec', 'libx264'])
plt.show()


import numpy as np
import scipy as sp
import matplotlib as mplt
import matplotlib.pyplot as plt

# Reading method 1
f=open("clalpha.dat","r")
atab = []
cltab = []
for line in f.readlines():
    numbers = line.split()
    atab.append(numbers[0])
    cltab.append(numbers[1])

# Reading method 2
table = np.genfromtxt("clalpha.dat",delimiter ="," , comments="C")

atab  = table[:,0]
cltab = table[:,1]

# Plotting the graph
plt.plot(atab,cltab)
plt.xlabel("alpha [deg]")
plt.ylabel("CL [-]")
plt.title("Lift coefficient")

plt.grid(True)
plt.show()

# Interpolation method 1: by hand

alpha = input("Give alpha:")
cl = None
for i in range(len(atab)-1):
    if atab[i]<alpha<=atab[i+1]:
        factor = (alpha - atab[i])/(atab[i+1]-atab[i])
        cl = (1-factor)*cltab[i]+factor*cltab[i+1]

if cl==None:
    print "Alpha",alpha,"out of range"
else:
    print "CL(",alpha,") =",cl

# Interpolation method 2: using Numpy

alpha = input("Give alpha:")
cl = np.interp(alpha, atab, cltab,left=-100.,right=-100.)

if cl>0:
    print "CL(",alpha,") =",cl
else:
    print "Alpha",alpha,"out of range"


"""
A3, Q2
Solving van der Pol oscillator using both Runge-Kutta and odeint,
taking odeint's result to be the true value
"""
import scipy.integrate as sp_int
import numpy as np
import matplotlib.pyplot as plt
from run_kut4 import *

# define constant
epsilon = 10.0
# inital conditions
x0 = 0.5
y0 = 0.0
ics = [x0,y0] #vector of initial conditions

# define the function as it demands
def f(x,y):
    f = np.zeros(2)
    f[0] = y[1] #f0 == dx, y[0] = x, y[1] = y
    f[1] = (-y[0])-((epsilon*((y[0]**2)-1))*y[1]) #f1 == dy
    return f

# integration parameters. These won't change
x_start = 0.0
x_stop = (10.0*np.pi)
# integration itself
X_002,Y_002 = integrate(f,x_start,ics,x_stop,0.02)

# plot
plt.figure(1)
plt.plot(X_002,Y_002[:,0],label=r'$h$ = 0.02',color='b')
plt.xlabel(r'time, $t$')
plt.ylabel(r'position, $x$')
plt.title(r'Position vs. time for step-size $h$ = 0.02')
plt.legend(loc=0)
plt.xlim(0,(10*np.pi))
plt.show()

# again for h=0.05
X_005,Y_005 = integrate(f,x_start,ics,x_stop,0.05)

plt.figure(2)
plt.plot(X_005,Y_005[:,0],label=r'$h$ = 0.05',color='g')
plt.xlabel(r'time, $t$')
plt.ylabel(r'position, $x$')
plt.title(r'Position vs. time for step-size $h$ = 0.05')
plt.xlim(0,(10*np.pi))
plt.legend(loc=0)
plt.show()

# again for h=0.1
X_01,Y_01 = integrate(f,x_start,ics,x_stop,0.1)

plt.figure(3)
plt.plot(X_01,Y_01[:,0],label=r'$h$ = 0.1', color='r')
plt.xlabel(r'time, $t$')
plt.ylabel(r'position, $x$')
plt.title(r'Position vs. time for step-size $h$ = 0.1')
plt.legend(loc=0)
#plt.ylim(-2.1,2.1)
plt.xlim(0,(10*np.pi))
plt.show()

# define equations for odeint
def odeint_f(q,t):
    xi = q[0]
    yi = q[1]
    f0 = yi
    f1 = (-xi)-((epsilon*((xi**2)-1))*yi)
    return [f0,f1]

# range to solve for
t = np.linspace(0,(10*np.pi), 100000) #make this huge to get pretty curves
# integrate using odeint
odeint_sol_10 = sp_int.odeint(odeint_f,ics,t)
x_ois_10 = odeint_sol_10[:,0]
y_ois_10 = odeint_sol_10[:,1]

# plot this solution
plt.figure(4)
plt.plot(t,x_ois_10, label='odeint', color='k')
plt.xlabel(r'time, $t$')
plt.ylabel(r'position, $x$')
plt.title(r'Position vs. time, using odeint')
plt.xlim(0,(10*np.pi))
plt.show()

# plot all four
plt.figure(5)
plt.plot(X_01,Y_01[:,0], label=r'RK: $h$ = 0.1', color='r') ##this blows up
plt.plot(X_005,Y_005[:,0], label=r'RK: $h$ = 0.05', color='g')
plt.plot(X_002,Y_002[:,0], label=r'RK: $h$ = 0.02', color='b')
plt.plot(t,x_ois_10, label='odeint', color='k')
plt.xlabel(r'time, $t$')
plt.ylabel(r'position, $x$')
plt.title('Position vs. time')
plt.legend(loc=0)
plt.xlim(0,(10*np.pi))
plt.ylim(-2.1,2.1)
plt.show()

# Errors.
# Both arrays need to be of equal size.
# Generate new true value arrays to match the size of the rk arrays

def trange(x):
    z = np.linspace(0,10*np.pi,len(x[:,0]))
    return z

truev_002 = sp_int.odeint(odeint_f,ics,trange(Y_002))
truev_005 = sp_int.odeint(odeint_f,ics,trange(Y_005))
truev_01 = sp_int.odeint(odeint_f,ics,trange(Y_01))

er_rk_002 = np.abs((truev_002[:,0]) - (Y_002[:,0]))
er_rk_005 = np.abs((truev_005[:,0]) - (Y_005[:,0]))
er_rk_01 = np.abs((truev_01[:,0]) - (Y_01[:,0]))

plt.figure(6)
plt.semilogy(trange(Y_002),er_rk_002, label=r'Error for RK sol with $h$ = 0.02')
plt.semilogy(trange(Y_005),er_rk_005, label=r'Error for RK sol with $h$ = 0.05')
plt.semilogy(trange(Y_01),er_rk_01, label=r'Error for RK sol with $h$ = 0.1')
plt.xlim(0,10*np.pi)
plt.title(r'Graph of log of absolute errors vs. $t$')
plt.xlabel(r'$t$, time')
plt.ylabel(r'semilog($\sigma$), absolute error')
plt.legend(loc=0)
plt.show()

plt.figure(7)
plt.semilogy(trange(Y_002),er_rk_002, label=r'Error for RK sol with $h$ = 0.02')
plt.semilogy(trange(Y_005),er_rk_005, label=r'Error for RK sol with $h$ = 0.05')
plt.xlim(0,10*np.pi)
plt.title(r'Graph of log of absolute errors vs. $t$')
plt.xlabel(r'$t$, time')
plt.ylabel(r'semilog($\sigma$), absolute error')
plt.legend(loc=0)
plt.show()

# C
# get epsilon = 4 sol
epsilon = 4.0
odeint_sol_4 = sp_int.odeint(odeint_f,ics,t)
x_ois_4 = odeint_sol_4[:,0]
y_ois_4 = odeint_sol_4[:,1]

# do again for epsilon = 1
epsilon = 1.0
odeint_sol_1 = sp_int.odeint(odeint_f,ics,t)
x_ois_1 = odeint_sol_1[:,0]
y_ois_1 = odeint_sol_1[:,1]

plt.figure(8)
plt.plot(x_ois_1,y_ois_1, label=r'$\epsilon$ = 1', color='b')
plt.plot(x_ois_4,y_ois_4, label=r'$\epsilon$ = 4', color='g')
plt.plot(x_ois_10,y_ois_10, label=r'$\epsilon$ = 10', color='r')
plt.axis('equal')
plt.title(r'Phase-space plot, $\frac{dx}{dt}$ vs. $x$')
plt.xlabel(r'$x$, position')
plt.ylabel(r'$\frac{dx}{dt}$, velocity')
plt.legend(loc=0)
plt.show()


# -*- coding: utf-8 -*-
"""
Created on Mon Oct 21 10:01:29 2019

@author: BSWOOD9321
"""

import numpy as np
import matplotlib.pyplot as plt

k=int(input('Enter a spring constant: '))
m=int(input('Enter a mass: '))
dt=.01
t=0
x=int(input('Enter a starting position: '))
v=int(input('Enter a starting velocity: '))
p=int(input('Enter an EVEN p-value between 2-12: '))
T=[t]
X=[x]
V=[v]

while t<15:
    f=-k*x**(p-1)
    v=v+(f/m)*dt
    x=x+v*dt
    t=t+dt
    T.append(t)
    X.append(x)
    V.append(v)

plt.plot(T,X,label='position')
plt.plot(T,V,label='velo')
plt.grid()
plt.legend(loc=(1.04,0))
plt.xlabel('Time')

plt.show()

## 1. Yes, I get the result that I expect, a sinusoidal pattern of the spring "bouncing" back and forth.
## 2. Yes, no matter what p value we choose, the solution does remain periodic with a constant amplitude. Some of them look really cool.
## 3. The mass has its highest velocity as the spring crosses "zero" in either direction. This does make sense as before this point,
## the mass is still acceleration faster, and after this point, it is de-accelerating until it reaches its maximum x value.
## 4. Yes, oscillators with different amplitudes have different periods. We can probably "design" two different amplitudes with the same periods,
## but it would require different masses and/or spring constants.

k1=3
m1=2
x1=0
v1=5
p1=2

while p1<=12:
    t1=0
    T1=[t1]
    X1=[x1]
    V1=[v1]
    while t1<15:
        f=-k1*x1**(p1-1)
        v1=v1+(f/m1)*dt
        x1=x1+v1*dt
        t1=t1+dt
        T1.append(t1)
        X1.append(x1)
        V1.append(v1)
    plt.plot(T1,X1,label='position')
    plt.plot(T1,V1,label='velo')
    plt.legend(loc=(1.04,0))
    plt.show()
    print('P=',p1,', k=3, m=2')
    p1=p1+2


#py_precision.py

"""A brief foray into the precision available with different numeric
   data types and some Python libraries you can use to wrangle them."""

#floats controlled by hardware; accurate to nearest binary value
print("simple addition: {} + {} + {} = {}".\
      format(.1, .1, .1,
             .1 + .1 + .1))
print()

#another example - these two are the same in binary
a = .1
b =  0.10000000000000001
print("does {} = {:.23f}?   {}".\
      format(a, b, a == b))
print()

#one solution:  store as a fraction
print("as fraction: {} + {} + {} = {}".\
      format(a, a, a,  (a + a + a).as_integer_ratio()))

print()
#better yet, use fractions library
import fractions
a = fractions.Fraction(1, 10)
print("using fractions.Fraction: {} + {} + {} = {}".\
      format(a, a, a,  (a + a + a)))

print()
#or use the decimal library
import decimal

#Accuracy is baked in when the (immutable) number is defined.

#   The accuracy is implied by the number of decimal places provided.
a = decimal.Decimal(".111111111111111111111111111111111111111111111111111111111111111111111"
                    "11111111111111111111111111111111111111111111111111111111111111111111"
                    "11111111111111111111111111111111111111111111111111111111111111111111"
                    "11111111111111111111111111111111111111111111111111111111111111111111"
                    "11111111111111111111111111111111111111111111111111111111111111111111"
                    "11111111111111111111111111111111111111111111111111111111111111111111")

#the 'context' is used to specify how much precision will be used in operations
decimal.getcontext().prec = 600
print("using decimal.Decimal:\n{}\n+\n{}\n+\n{}\n=\n{}".\
      format(a, a, a,
             a + a + a))

#and you can always 'sqeeze it down' into a fixed precision
print()
quant_num =  a.quantize(decimal.Decimal('0.001'))
print("quantized:  a = {}".format(quant_num))

print()

#Integers are inherently accurate.  There is no theoretical size limit
# except practical (system constrained).  How big?
import sys

print("maximum Python integer supported on this box: {}".format(sys.maxsize))

print()
#In numpy (scipy) different object types have different limitations
import numpy
print("numpy integers available on this box:")
for dtype in numpy.sctypes['int']:
	info =  numpy.iinfo(dtype)
	print("dtype: {}  max: {}".format(info.dtype, info.max))


from sympy import *

q0, q1, q2, q3 = symbols('q0 q1 q2 q3')
quaternion_symbols = [q0, q1, q2, q3]
target_value = 1
model_function = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3)
delta = Matrix([target_value - model_function]).vec()
delta_jacobian = delta.jacobian(quaternion_symbols)

print(delta)
print(delta_jacobian)

with open("quaternion_constraint_jacobian.h",'w') as f_cpp:
    f_cpp.write("inline void quaternion_constraint(double &delta, double q0, double q1, double q2, double q3)\n")
    f_cpp.write("{")
    f_cpp.write("delta = %s;\n"%(ccode(delta[0,0])))
    f_cpp.write("}")
    f_cpp.write("\n")
    f_cpp.write("inline void quaternion_constraint_jacobian(Eigen::Matrix<double, 1, 4> &j, double q0, double q1, double q2, double q3)\n")
    f_cpp.write("{")
    for i in range (1):
        for j in range (4):
            f_cpp.write("j.coeffRef(%d,%d) = %s;\n"%(i,j, ccode(delta_jacobian[i,j])))
    f_cpp.write("}")


"""
Metrics for distances and losses
"""

import numpy as np

def euclidean_distance(a, b):
    """
    Euclidean distance: https://en.wikipedia.org/wiki/Euclidean_distance
    """

    squared_diff = (a - b) ** 2
    sum_squared_diff = np.sum(squared_diff)
    return np.sqrt(sum_squared_diff)

def mean_squared_error(y_true, y_pred):
    """Compute the Mean Squared Error between two vectors."""

    return np.square(y_true - y_pred).mean()


import numpy as np

def softmax(output):
  return np.transpose(np.exp(np.transpose(output)) / np.sum(np.exp(output), axis=1))

def ce_loss(output, label):
  return np.mean(-np.sum(label * np.log(output), axis=1))

def grad(input, output, label):
  return (-1/input.shape[0])*(np.transpose(input)@(label - output))

def softmax_classifier(w, input, label, lamda):
    """
      Softmax Classifier

      Inputs have dimension D, there are C classes, a minibatch have N examples.
      (In this homework, D = 784, C = 10)

      Inputs:
      - w: A numpy array of shape (D, C) containing weights.
      - input: A numpy array of shape (N, D) containing a minibatch of data.
      - label: A numpy array of shape (N, C) containing labels, label[i] is a
        one-hot vector, label[i][j]=1 means i-th example belong to j-th class.
      - lamda: regularization strength, which is a hyerparameter.

      Returns:
      - loss: a single float number represents the average loss over the minibatch.
      - gradient: shape (D, C), represents the gradient with respect to weights W.
      - prediction: shape (N, 1), prediction[i]=c means i-th example belong to c-th class.
    """

    ############################################################################
    # TODO: Put your code here
    # Output -> Softmax of W*X
    output = softmax(input @ w)
    # Loss -> Cross-entropy + Regularization
    loss = ce_loss(output, label) + (lamda/2)*np.linalg.norm(w)
    # Softmax gradient
    gradient = grad(input, output, label)
    # Predicted label
    prediction = np.argmax(output, axis=1)
    ############################################################################

    return loss, gradient, prediction


import numpy as np

def cart2sph(x,y,z):
    '''
    直角坐标转化为球坐标，但此处的[x,y,z]对应标准球坐标系中的[y,z,x]

    输入:
        * x,y,z 直角坐标

    输出:
        * azimuth, elevation, r 角度值的球坐标
    '''
    r2d = 180.0/np.pi
    azimuth = np.arctan2(x,z)*r2d
    elevation = np.arctan2(y,np.sqrt(z**2 + x**2))*r2d
    r = np.sqrt(z**2 + x**2 + y**2)
    return [azimuth, elevation, r]

def sph2cart(azimuth,elevation,r):
    '''
    球坐标转化为直角坐标，但此处的[x,y,z]对应标准球坐标系中的[y,z,x]

    输入:
        * azimuth, elevation, r 角度值的球坐标

    输出:
        * x,y,z 直角坐标
    '''
    d2r = np.pi/180.0
    z = r * np.cos(elevation*d2r) * np.cos(azimuth*d2r)
    x = r * np.cos(elevation*d2r) * np.sin(azimuth*d2r)
    y = r * np.sin(elevation*d2r)
    return [x, y, z]