"""
Copyright 2013 Steven Diamond

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

from __future__ import division
import sys

import cvxopt
import numpy as np
from scipy import sparse
from pylab import *
import math

from cvxpy import *
from multiprocessing import Pool

# Taken from CVX website http://cvxr.com/cvx/examples/
# Figure 6.9: An optimal tradeoff curve
# Ported from cvx matlab to cvxpy by Misrab Faizullah-Khan
# Original comments below

# Section 6.3.3
# Boyd & Vandenberghe "Convex Optimization"
# Original by Lieven Vandenberghe
# Adapted for CVX Joelle Skaf - 09/29/05
# (a figure is generated)
#
# Plots the optimal trade-off curve between ||Dx||_2 and ||x-x_cor||_2 by
# solving the following problem for different values of delta:
#           minimize    ||x - x_cor||^2 + delta*||Dx||^2
# where x_cor is the a problem parameter, ||Dx|| is a measure of smoothness

# Input data
n = 400
t = np.array(range(0,n))

exact = 0.5*sin(2*np.pi*t/n) * sin(0.01*t)
corrupt = exact + 0.05 * np.random.randn(len(exact))
corrupt = cvxopt.matrix(corrupt)

e = np.ones(n).T
ee = np.column_stack((-e,e)).T
D = sparse.spdiags(ee, range(-1,1), n, n)
D = D.todense()
D = cvxopt.matrix(D)

# Solve in parallel
nopts = 10
lambdas = np.linspace(0, 50, nopts)
# Frame the problem with a parameter
lamb = Parameter(nonneg=True)
x = Variable(n)
p = Problem( Minimize( norm(x-corrupt) + norm(D*x) * lamb ) )

# For a value of lambda g, we solve the problem
# Returns [ ||Dx||_2 and ||x-x_cor||_2 ]
def get_value(g):
	lamb.value = g
	result = p.solve()
	return [np.linalg.norm( x.value - corrupt ), np.linalg.norm(D*x.value) ]

pool = Pool(processes = 4)
# compute allocation in parallel
norms1, norms2 = zip(*pool.map(get_value, lambdas))

plot(norms1, norms2)
xlabel('||x - x_{cor}||_2')
ylabel('||Dx||_2')
title('Optimal trade-off curve')
show()


import numpy as np

import autodiff as ad

t = 1e-8

def noise_like(x):
  return np.random.uniform(-1, 1, np.shape(x))

def run_problem3():
  print("-" * 18 + " Problem 3 " + "-" * 18)
  x = ad.Variable()
  w1 = ad.Variable()
  w2 = ad.Variable()
  y = ad.average(ad.matmul(ad.relu(ad.matmul(x, w1)), w2) + x)

  x_f = np.random.randn(1, 64)
  w1_f = np.random.randn(64, 128)
  w2_f = np.random.randn(128, 64)

  x_v = noise_like(x_f)
  w1_v = noise_like(w1_f)
  w2_v = noise_like(w2_f)

  f, grad = ad.func(y, {x: x_f, w1: w1_f, w2: w2_f}, get_gradient=True)
  f_np = np.average(np.matmul(np.maximum(np.matmul(x_f, w1_f), 0), w2_f) + x_f)
  print("Function value by autodiff =", f)
  print("Function value by numpy    =", f_np)

  lhs = (ad.func(y, {x: x_f + t * x_v, w1: w1_f + t * w1_v,
                     w2: w2_f + t * w2_v}) - f) / t
  rhs = (np.sum(grad[x] * x_v) + np.sum(grad[w1] * w1_v)
         + np.sum(grad[w2] * w2_v))
  print("(V(w + tv)-V(w)) / t       =", lhs)
  print("<dV(w), v>                 =", rhs)
  print("|lfs - rhs| / |lhs|        =", np.abs(lhs - rhs) / np.abs(lhs))

def run_problem4():
  print("-" * 18 + " Problem 4 " + "-" * 18)
  x1 = ad.Variable()
  x2 = ad.Variable()
  x3 = ad.Variable()
  y = ((ad.sin(x1 + 1) + ad.cos(2 * x2)) * ad.tan(ad.log(x3))
       + (ad.sin(x2 + 1) + ad.cos(2 * x1)) * ad.exp(1 + ad.sin(x3)))

  x1_f = np.random.rand()
  x2_f = np.random.rand()
  x3_f = np.random.rand()

  x1_v = noise_like(x1_f)
  x2_v = noise_like(x2_f)
  x3_v = noise_like(x3_f)

  f, grad = ad.func(y, {x1: x1_f, x2: x2_f, x3: x3_f}, get_gradient=True)
  f_np = ((np.sin(x1_f + 1) + np.cos(2 * x2_f)) * np.tan(np.log(x3_f))
          + (np.sin(x2_f + 1) + np.cos(2 * x1_f)) * np.exp(1 + np.sin(x3_f)))
  print("Function value by autodiff =", f)
  print("Function value by numpy    =", f_np)

  lhs = (ad.func(y, {x1: x1_f + t * x1_v, x2: x2_f + t * x2_v,
                     x3: x3_f + t * x3_v}) - f) / t
  rhs = (np.sum(grad[x1] * x1_v) + np.sum(grad[x2] * x2_v)
         + np.sum(grad[x3] * x3_v))
  print("(V(w + tv)-V(w)) / t       =", lhs)
  print("<dV(w), v>                 =", rhs)
  print("|lfs - rhs| / |lhs|        =", np.abs(lhs - rhs) / np.abs(lhs))

if __name__ == '__main__':
  run_problem3()
  run_problem4()


#! /usr/bin/env python

# Author: Srinivasa Rao Zinka (srinivas . zinka [at] gmail . com)
# Copyright (c) 2014 Srinivasa Rao Zinka
# License: New BSD License.

import numpy as np
from scipy import integrate

def FS(fun_str_re, fun_str_im='0', T0=2 * np.pi, m_start=-5, m_stop=5, err_lim=1e-8):
    """Function to generate a finite number of Fourier series coefficients of
    a periodic function."""

    N = m_stop - m_start + 1
    FS = np.zeros((N, 1), dtype='complex')
    m_index = range(m_start, m_stop + 1)
    w0 = 2 * np.pi / T0

    for m in m_index:
        fun_re = lambda x: (eval(fun_str_re)) * np.cos(m * w0 * x) + (eval(fun_str_im)) * np.sin(m * w0 * x)
        fun_img = lambda x: -(eval(fun_str_re)) * np.sin(m * w0 * x) + (eval(fun_str_im)) * np.cos(m * w0 * x)
        FS_re = integrate.quad(fun_re, 0, 2 * np.pi)
        FS_img = integrate.quad(fun_img, 0, 2 * np.pi)
        if ((FS_re[1] + FS_img[1]) < err_lim):
            FS[m - m_start] = (1 / T0) * (FS_re[0] + 1j * FS_img[0])
        else:
            print
            "Absolute error of the integration is not less than 1e-10 while calculating Fourier series"
            print
            "error(FS_re): ", FS_re[1]
            print
            "error(FS_img): ", FS_img[1]
        m_index = np.array(m_index) * (2 * np.pi / T0)
        m_index = np.reshape(m_index, (m_index.size, -1))

    return m_index, FS

def IFS(FS, T0=2 * np.pi, m_start=-4, m_stop=4, x_min=0, x_max=2 * np.pi, x_num=10):
    """Function to reconstruct (or check) the periodic function from the
    obtained Fourier coefficients"""

    m = np.arange(m_start, m_stop + 1)
    m = np.reshape(m, (-1, m.size))
    M = np.tile(m, (x_num, 1))
    x = np.linspace(x_min, x_max, num=x_num)
    x = np.reshape(x, (x.size, -1))
    X = np.tile(x, (1, m.size))
    FS = np.reshape(FS, (FS.size, -1))
    # Evaluating the inverse of the Fourier series
    IFS = np.dot(np.exp(1j * M * (2 * np.pi / T0) * X), FS)

    return x, IFS

if __name__ == '__main__':


# coding=utf-8
""" Compute Cost Function
 Maliyet Fonksiyonunu Hesapla"""

import numpy as np

def squarred_error_maliyet_hesapla(x, y, teta):
    """

    :param x: Ongorucu Degisken, Ev Buyuklukleri
    :param y: Hedef Degisken, Ev Fiyatlari
    :param teta: parametre
    :return: maliyet
    """
    m = len(x)
    toplamin_acilimi = np.power(((x * teta.T) - y), 2)
    maliyet = np.sum(toplamin_acilimi) / (2 * m)
    return maliyet

def mae_maliyet_fonksiyonu_hesapla(x, y, teta):
    """

    :param x: Ongorucu Degisken, Ev Buyuklukleri
    :param y: Hedef Degisken, Ev Fiyatlari
    :param teta: parametre
    :return: maliyet
    """
    m = len(x)
    toplamin_acilimi = np.abs(((x * teta.T) - y))
    maliyet = np.sum(toplamin_acilimi) / m
    return maliyet

def mse_maliyet_fonksiyonu_hesapla(x, y, teta):
    """

    :param x: Ongorucu Degisken, Ev Buyuklukleri
    :param y: Hedef Degisken, Ev Fiyatlari
    :param teta: parametre
    :return: maliyet
    """
    m = len(x)
    toplamin_acilimi = np.power(((x * teta.T) - y), 2)
    maliyet = np.sum(toplamin_acilimi) / m
    return maliyet

def rmse_maliyet_fonksiyonu_hesapla(x, y, teta):
    """

    :param x: Ongorucu Degisken, Ev Buyuklukleri
    :param y: Hedef Degisken, Ev Fiyatlari
    :param teta: parametre
    :return: maliyet
    """
    m = len(x)
    toplamin_acilimi = np.power(((x * teta.T) - y), 2)
    maliyet = np.sqrt(np.sum(toplamin_acilimi) / m)
    return maliyet

Bölüm 3 : Regresyon/3.4 cok degiskenli lineer regresyon/mini_batch_gradient_with_momentum/maliyet_hesapla.py


import numpy as np

def sinkhorn_knopp(a, b, M, reg, numItermax=1000,
                   stopThr=1e-9, verbose=False, log=False, **kwargs):

    a = np.asarray(a, dtype=np.float64)
    b = np.asarray(b, dtype=np.float64)
    M = np.asarray(M, dtype=np.float64)

    if len(a) == 0:
        a = np.ones((M.shape[0],), dtype=np.float64) / M.shape[0]
    if len(b) == 0:
        b = np.ones((M.shape[1],), dtype=np.float64) / M.shape[1]

    # init data
    dim_a = len(a)
    dim_b = len(b)

    #if len(b.shape) > 1:
    #    n_hists = b.shape[1]
    #else:
    #    n_hists = 0

    if log:
        log = {'err': []}#, 'loss': []}

    # we assume that no distances are null except those of the diagonal of
    # distances
    #if n_hists:
    #    u = np.ones((dim_a, n_hists)) / dim_a
    #    v = np.ones((dim_b, n_hists)) / dim_b
    #else:
    u = np.zeros(dim_a, dtype=np.float64) #/ dim_a; #u = np.log(u) # log to match linear-scale sinkhorn initializations
    v = np.zeros(dim_b, dtype=np.float64) #/ dim_b; #v = np.log(v)

    # print(reg)

    # Next 3 lines equivalent to K= np.exp(-M/reg), but faster to compute
    K = np.empty(M.shape, dtype=M.dtype)
    np.divide(M, -reg, out=K)
    np.exp(K, out=K)

    #print(np.exp(u).shape, np.exp(v).shape, K.shape)
    B = np.einsum('i,ij,j->ij', np.exp(u), K, np.exp(v))
    ones_a = np.ones(dim_a, dtype=np.float64)
    ones_b = np.ones(dim_b, dtype=np.float64)

    # print(np.min(K))
    #tmp2 = np.empty(b.shape, dtype=M.dtype)

    #Kp = (1 / a).reshape(-1, 1) * K
    cpt = 0
    err = 1
    while (err > stopThr and cpt < numItermax):
        uprev = u
        vprev = v

        #KtransposeU = np.dot(K.T, u)
        #v = np.divide(b, KtransposeU)
        #u = 1. / np.dot(Kp, v)

        #B = np.einsum('i,ij,j->ij', np.exp(uprev), K, np.exp(vprev))
        if cpt%2 == 0:
            u = uprev + np.log(a) - np.log(np.matmul(ones_b, B.T)+ 1e-299) #transpose-row
            v = vprev
        else:
            v = vprev + np.log(b) - np.log(np.matmul(ones_a, B)+ 1e-299)
            u = uprev
        #print(np.exp(u).shape, np.exp(v).shape, K.shape)
        B = np.einsum('i,ij,j->ij', np.exp(u), K, np.exp(v))

        if (np.any(np.isnan(u)) or np.any(np.isinf(u))
                or np.any(np.isnan(v)) or np.any(np.isinf(v))
                or np.any(np.isnan(B)) or np.any(np.isinf(B))):
            # we have reached the machine precision #np.any(KtransposeU == 0)
            # come back to previous solution and quit loop
            print('Warning: numerical errors at iteration', cpt)
            u = uprev
            v = vprev
            B = np.einsum('i,ij,j->ij', np.exp(u), K, np.exp(v))
            break
        if cpt % 10 == 0: #10
            # we can speed up the process by checking for the error only all
            # the 10th iterations
            #if n_hists:
            #    np.einsum('ik,ij,jk->jk', u, K, v, out=tmp2)
            #else:
            # compute right marginal tmp2= (diag(u)Kdiag(v))^T1
            #np.einsum('i,ij,j->j', u, K, v, out=tmp2)

            #B = np.einsum('i,ij,j->ij', np.exp(u), K, np.exp(v))
            #err = np.linalg.norm(tmp2 - b)  # violation of marginal
            err = np.linalg.norm(np.matmul(ones_b, B.T)-a, ord=1) + \
                    np.linalg.norm(np.matmul(ones_a, B)-b, ord=1)

            #loss = np.sum(round(B, a, b)*C)
            if log:
                log['err'].append(err)

            if verbose:
                if cpt % 200 == 0:
                    print(
                        '{:5s}|{:12s}'.format('It.', 'Err') + '\n' + '-' * 19)
                print('{:5d}|{:8e}|'.format(cpt, err))
        cpt = cpt + 1
    if log:
        log['u'] = u
        log['v'] = v

    '''if n_hists:  # return only loss
        res = np.einsum('ik,ij,jk,ij->k', u, K, v, M)
        if log:
            return res, log
        else:
            return res

    else:  # return OT matrix'''

    if log:
        #return u.reshape((-1, 1)) * K * v.reshape((1, -1)), log
        return B, cpt, log
    else:
        #return u.reshape((-1, 1)) * K * v.reshape((1, -1))
        return B, cpt


"""
Homework problem 1
"""

import numpy as np
from matplotlib import pyplot as plt
from scipy import optimize as opt

def washboard(var, tilt):
    return 5*np.cos(var) + np.cos(2*var) - tilt*var

def part_a():
    x = np.linspace(-2, 0, 1000)
    F = 6
    x_max = opt.minimize_scalar(lambda var: -washboard(var, F), bounds=(-1.5, 0), method='bounded').x
    x_min = opt.minimize_scalar(lambda var: washboard(var, F), bounds=(-3, -1), method='bounded').x
    plt.figure()
    plt.grid()
    plt.plot(x, washboard(x, F), label='Washboard potential')
    plt.scatter(x_max, washboard(x_max, F), c='g', label=f'Max = {round(x_max, 7)}')
    plt.scatter(x_min, washboard(x_min, F), c='r', label=f'Min = {round(x_min, 7)}')
    plt.legend()
    plt.show()
    print(x_max)
    print(x_min)
    print(washboard(x_max, F) - washboard(x_min, F))

def part_b():
    def f(vec):
        var, tilt = vec
        return -5 * np.sin(var) - 2 * np.sin(2 * var) - tilt, -5 * np.cos(var) - 4 * np.cos(2 * var)
    rc, Fc = opt.root(f, x0=np.array([-1, 6])).x
    print(rc)
    print(Fc)

if __name__ == '__main__':
    print('COMMIT!!!!')
    part_b()


#! /usr/local/python27/bin/python

# For Codor -
# Setting up some

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import scipy.integrate as integrate
import random as rdm

def gaussprof(A,hw,x,x0):

      # A function based on the matlab code of
      # Codor Khodr (Uni. of Bristol) to generate the
      # a Gaussian hill topography profile

      # Input:
	# A = maximum altitude of the Gaussian function
	# hw = half-width (standard deviation) of Gaussian
	# x = input abssica
	# x0 = center of the Gaussian Hill

      # Output:
      # f -> the Gaussian hill function, i.e., f(x)

	# Generate the Gaussian

	n = x.shape[0]
	f = np.zeros(n)

      # Codor's function parameterised in terms of theta_max. Why?
	#A = np.tan(theta_max*np.pi/180.0)*d*np.exp(0.5)/np.sqrt(2)
	#print 'A = ',A

	for i in range(n):
		f[i] = A*np.exp(-1*((x[i]-x0)**2)/(2*(hw**2)))

	return f

def gaussprof3D(A,hwx,hwy,x,y,x0,y0):

    # Create a 3D Gaussian Hill
    # A function based on the matlab code of
    # Codor Khodr (Uni. of Bristol) to generate the
    # a Gaussian hill topography profile

    # Input:
    # A = maximum height of the Gaussian Hill
    # hwx = half-width (standard deviation) of Gaussian in x-dirn
    # hwy = half-width (standard deviation) of Gaussian in y-dirn
    # x = input abssica
    # x0 = center of the Gaussian Hill

    # Output:
    # f -> the Gaussian hill function, i.e., f(x)

    # Create the mesh and calculate the Gaussian function
    xv,yv = np.meshgrid(x,y)
    # Flattening (inefficient programming step?)
    xvflat = xv.flatten()
    yvflat = yv.flatten()

    n = len(xvflat)
    f = np.zeros(n)

    for i in range(n):
        term1 = ((xvflat[i]-x0)**2)/(2*(hwx**2))
        term2 = ((yvflat[i]-y0)**2)/(2*(hwy**2))
        f[i]  = A*np.exp(-1*(term1+term2))

    return xvflat,yvflat,f

#----- Main Prog

#---------------------------------------------------------------
# Setting up the Gaussian, as per Codor's email of 10-March-2016
#
# Calculating path length using the standard formula
# p.29 of Riley, Hobson and Bence
#---------------------------------------------------------------
para = {'axes.labelsize': 16, 'text.fontsize': 16, 'legend.fontsize': 14, 'xtick.labelsize': 14,'ytick.labelsize': 14, 'figure.subplot.left': 0.12, 'figure.subplot.right': 0.98, 'figure.subplot.bottom': 0.11, 'figure.subplot.top': 0.97}
plt.rcParams.update(para)

#-----------
# 2D CASES
#-----------

L = 6000.
A = 200.
dx = 90.
x0 = L/2.0
hw = 3.0*A

x_regular = np.arange(0,L,dx)

# Calculating the regular topography function.

f_regular = gaussprof(A,hw,x_regular,x0)

fig = plt.figure(figsize=(6,6))
ax1 = fig.add_axes([0.2,0.2,0.7,0.7])

ax1.plot(x_regular,f_regular,'ko')

plt.xlabel('x (m)')
plt.ylabel('y (m)')

# Calculating the irregularly sampled topography function

x_irregular = np.sort(rdm.sample(range(0,int(L)),len(x_regular)))

f_irregular = gaussprof(A,hw,x_irregular,x0)

ax1.plot(x_irregular,f_irregular,'r*')
plt.show()

#-----------------------------------------------------------------
# Now to output to ASCII files
#-----------------------------------------------------------------
dirpath = '/Users/dgreen/Documents/Work/4codor/infratopo/topo_input_files/synthetics/'

regfile = 'gauss_'+str(int(A))+'m_hill_short.dat'
irregfile = 'gauss_'+str(int(A))+'m_hill_irreg_short.dat'
flatfile = 'flat_topo_short.dat'

fr = open(dirpath+regfile, 'w')
for x in range(len(f_regular)):
    fr.write('{:4.0f} {:5.1f}\n'.format(x_regular[x],f_regular[x]))
fr.close()

fi = open(dirpath+irregfile, 'w')
for x in range(len(f_irregular)):
    fi.write('{:4.0f} {:5.1f}\n'.format(x_irregular[x],f_irregular[x]))
fi.close()

ff = open(dirpath+flatfile, 'w')
for x in range(len(f_regular)):
    ff.write('{:4.0f} {:5.1f}\n'.format(x_regular[x],0.0))
ff.close()

#-----------------------------------------------------------------
# Now for the long-range cases (500km)
#-----------------------------------------------------------------

L = 550000.
A = 3000.
dx = 1000.
x0 = 250000.
hw = 60000.

x_regular = np.arange(0,L,dx)

# Calculating the regular topography function.

f_regular = gaussprof(A,hw,x_regular,x0)

fig = plt.figure(figsize=(6,6))
ax1 = fig.add_axes([0.2,0.2,0.7,0.7])

ax1.plot(x_regular,f_regular,'ko')

plt.xlabel('x (m)')
plt.ylabel('y (m)')

dirpath = '/Users/dgreen/Documents/Work/4codor/infratopo/topo_input_files/synthetics/'

longfile = 'gauss_'+str(int(A))+'m_hill_long.dat'
fr = open(dirpath+longfile, 'w')
for x in range(len(f_regular)):
    fr.write('{:6.0f} {:5.1f}\n'.format(x_regular[x],f_regular[x]))
fr.close()

longflat = 'flat_topo_long.dat'
fr = open(dirpath+longflat, 'w')
for x in range(len(f_regular)):
    fr.write('{:6.0f} {:5.1f}\n'.format(x_regular[x],0.0))
fr.close()

#-----------
# 3D CASES
#-----------

L = 6000.
A = 200.
dx = 90.
dy = dx
x0 = L/2.0
y0 = L/2.0
hwx = 3.0*A
hwy = 3.0*A

x_regular = np.arange(0,L,dx)
y_regular = np.arange(0,L,dy)

xv3d,yv3d,f3d = gaussprof3D(A,hwx,hwy,x_regular,y_regular,x0,y0)

# For plottting (not ascii output) need to convert above to 2D arrays

cols = np.unique(xv3d).shape[0]
X = xv3d.reshape(-1, cols)
Y = yv3d.reshape(-1, cols)
Z = f3d.reshape(-1, cols)

fig = plt.figure()
#ax = fig.add_subplot(111, projection='3d')
ax = fig.add_axes([0.25, 0.25, 0.75, 0.75], projection='3d')
ax.set_zlabel('Alt (m)')
ax.set_ylabel('y (m)')
ax.set_xlabel('x (m)')
surf = ax.plot_surface(X,Y,Z,rstride=2,cstride=2,cmap=cm.coolwarm,linewidth=0, antialiased=False)
#fig.colorbar(surf, shrink=0.4, aspect=10)
ax.dist=11

plt.show()
fig.savefig('gauss_3D_example_crude.png',bbox_inches='tight')

# Output to ASCII
regfile3d = 'gauss3d_'+str(int(A))+'m_hill_short.dat'
flatfile3d = 'flat_topo_3d_short.dat'

fr3d = open(dirpath+regfile3d, 'w')
for x in range(len(f3d)):
    fr3d.write('{:4.0f} {:4.0f} {:5.1f}\n'.format(xv3d[x],yv3d[x],f3d[x]))
fr3d.close()

fl3d = open(dirpath+flatfile3d, 'w')
for x in range(len(f3d)):
    fl3d.write('{:4.0f} {:4.0f} {:5.1f}\n'.format(xv3d[x],yv3d[x],0.0))
fl3d.close()


#### Logistic regression with regularizaion optimized by BFGS algorithm

### author: Dr. Marko Mitic
### year: 2015
### contact: miticm@gmail.com

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

class LRREG:

    def __init__(self, data):
        self.x=data[:,0:-1]
        self.y=data[:,-1]
        self.m=len(data)
        self.C1=0.1 #regularization parameter

    def plotdata(self):
        plot1=self.x[np.where(self.y==1)]
        plot2=self.x[np.where(self.y==0)]
        ###
        plt.figure()
        plt.plot(plot1[:,0], plot1[:,-1],'bo', label='Admitted')
        plt.plot(plot2[:,0], plot2[:,-1],'ro', label='Not admitted')
        #plt.legend()
        plt.show()

    def mapfeatures(self,x): #building polynomial features

        degree=6
        X1=x[:,0]
        X2=x[:,1]

        X1.shape=(len(X1),1)
        X2.shape=(len(X2),1)

        m=np.shape(x[:,0])[0]
        newfeatures = np.ones(shape=(m,1))

        for i in range(1, degree + 1):
            for j in range(i + 1):
                r = (X1 ** (i - j)) * (X2 ** j)
                newfeatures = np.append(newfeatures, r, axis=1)

        return newfeatures

    def sigmoid(self,z):

        return 1./(1+np.exp(-z))

    def costandgradient(self, theta, x, y):

        z=np.dot(x,theta)
        hypothesis=self.sigmoid(z)

        ##compute cost
        firstterm=np.dot(y,np.log(hypothesis))
        secondterm=np.dot((1-y), np.log(1-hypothesis))

        J=(-1./self.m)*(firstterm+secondterm) + (self.C1/(2*self.m))*(sum(theta[1:len(theta)]**2)) ###second part is for regularization

        ##compute gradient
        grad0=(1./self.m)*np.dot((hypothesis-y),x[:,0])
        gradrest=(1./self.m)*np.dot((hypothesis-y),x[:,1:np.shape(x)[1]]) + (self.C1/self.m)*theta[1:len(theta)] ###second part is for regularization

        grad=np.append(grad0, gradrest)

        return [J, grad]

    def predict(self,theta,x):

        z=np.dot(x,theta)
        hypothesis=self.sigmoid(z)

        p=np.zeros(len(z))

        for i in range(0,len(z)):

            if hypothesis[i]>0.5:
                p[i]=1
            else:
                p[i]=0

        return p

    ###TODO:plot the nonlinear hypothesis

################################################################################
def runLR():
    data = np.loadtxt("data_LogisticR2.txt", comments="#", delimiter=",", unpack=False)

    lr=LRREG(data)
    lr.plotdata()

    X=lr.x
    y=lr.y

    X=lr.mapfeatures(X)
    initial_theta=np.zeros(X.shape[1])
    [J, grad]=lr.costandgradient(initial_theta, X, y)

    opt_solution = optimize.minimize(lr.costandgradient, initial_theta, args = (X,y), method = 'L-BFGS-B', jac = True, options = {'maxiter': 500})

    theta=opt_solution.x

    p=lr.predict(theta,X)

    accuracy=(np.mean(p==y))*100

    return theta, accuracy

[theta, accuracy]=runLR()

print 'Optimal parameters found by LR with BFGS algorithm are', theta
print 'Learning accuracy is', accuracy


''' This is an explicit 5th order Runge-Kutta solver for the time
    iteration based on the code in the Jupyter notebook:FDTransient
    of the class, and an adaptive error control is embedded
'''
import numpy as np
import pandas
from fractions import Fraction
from matplotlib import pyplot as plt
from numpy import linalg as LA

def adp_RK(RHS, u0, tfinal, h, p, e):  #u0 is the initial value , p is the order of the method, e is the tolerence
    def RKF():
        dframe = pandas.read_html('https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta%E2%80%93Fehlberg_method')[0]
        # Clean up unicode minus sign, NaN, and convert to float
        dfloat = dframe.applymap(lambda s: s.replace('−', '-') if isinstance(s, str) else s) \
            .fillna(0).applymap(Fraction).astype(float)

        # Extract the Butcher table
        darray = np.array(dfloat)
        A_RKF = darray[:6,2:]
        b_RKF = darray[6:,2:]
        return A_RKF , b_RKF[0,:] , b_RKF[1,:]

    A, b1, b2 = RKF()
    c = np.sum(A, axis=1)      # vector of abscissa
    s = len(c)                 # number of stages
    u   = u0.copy()
    u_e = u0.copy()            # initialize the error control vector
    t = 0
    hist = [(t,u0)]            # the initial status pair

    ########__decide the final step size__########
    while t < tfinal:
        if tfinal - t < 1.01*h:
            h = tfinal - t
            tnext = tfinal
        else:
            tnext = t + h
        h = min(h, tfinal - t)
    ##############################################

        fY = np.zeros((len(u0), s))                  #the approximation matrix at t = t + h, col for each stage
        for i in range(s):                           # i = 0,1,2...s-1
            Yi = u.copy()
            for j in range(i):
                Yi += h * A[i,j] * fY[:,j]
            fY[:,i] = RHS(t + h*c[i], Yi).ravel()

        e_loc =  LA.norm (h * fY @ (b1-b2), np.inf)
        c_loc  =  e_loc/(h**p)
        h_star =  np.power(e/c_loc,1/p)
        #print(e_loc-e,h,t)
        if (e_loc>=e) and (h_star>=0.0005):
            h = h_star* 0.5                                    # Safe factor  =  0.1

        else:
            u     += h * fY @ b1
            t = tnext
            hist.append((t, u.copy()))

    return hist


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

import numpy as np
import matplotlib.pyplot as plt

def true_state_value(probability):
    """
    compute the true value of the first state according to dynamics
    :param probability: the probability of right action
    :return: the true value

    V(S1)=p*1*(-1+V(S2))+(1-p)*1*(-1+V(S1))
    V(S2)=p*1*(-1+V(S1))+(1-p)*1*(-1+V(S3))
    V(S3)=p*1*(-1+0)+(1-p)*1*(-1+V(S2))
    p is the probability of right action
    ===>       V(S1) = 2*(p-2)/(p*(1-p))
    """
    return 2*(probability-2)/(probability*(1-probability))

if __name__ == "__main__":
    epsilon = 0.1           # the epsilon-greedy
    probability_range = np.linspace(0.03, 0.98, 100)        # set the probability of right action
    state_value = true_state_value(probability_range)       # get the true state value

    idx_max = np.argmax(state_value)            # get the index of the maximum of state value

    plt.figure(1)
    plt.plot(probability_range, state_value, "k")
    plt.plot(probability_range[idx_max], state_value[idx_max], "ro", label=r"optimal stochastic policy")
    plt.plot(epsilon/2, true_state_value(epsilon/2), "bo", label=r"$\epsilon$-greedy left")
    plt.plot(1-epsilon/2, true_state_value(1-epsilon/2), "go", label=r"$\epsilon$-greedy right")
    plt.ylim(-100)
    plt.xlabel("Probability of right action")
    plt.ylabel("True Value of First State")
    plt.legend()
    plt.savefig("./images/Example13-1.png")
    plt.show()
    plt.close()


"""
several active functions:
ReLU
Sigmoid
LeakyReLU
Softmax
Tanh
"""
import numpy as np

class ReLU:
    def __init__(self):
        self.middle = None

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

    def forward(self, x):
        self.middle = x > 0
        return self.middle * x

    def backward(self, grad_in):
        return grad_in * self.middle

    def __repr__(self):
        return "Active Function : ReLU"

class Sigmoid:
    def __init__(self):
        self.middle = None

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

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

    def backward(self, grad_in):
        return grad_in * self.middle * (1 - self.middle)

    def __repr__(self):
        return "Active Function : Sigmoid"

class LeakyReLU:
    def __init__(self, slope=0.1):
        self.middle = None
        self.slope = slope

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

    def forward(self, x):
        self.middle = x > 0
        return self.middle * x + (1 - self.middle) * self.slope * x

    def backward(self, grad_in):
        return self.middle * grad_in + (1 - self.middle) * self.slope * grad_in

    def __repr__(self):
        return "Active Function : LeakyReLU"

class Softmax:
    def __init__(self):
        self.middle = None

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

    def forward(self, x):
        # default : rows represent the different samples
        #           cols represent the scores
        x = x - np.max(x, axis=1, keepdims=True)            # prevent the boom
        self.middle = np.exp(x) / np.sum(np.exp(x), axis=1, keepdims=True)
        return self.middle

    def backward(self, grad_in):
        temp = np.sum(grad_in * self.middle, axis=1, keepdims=True)
        return self.middle * grad_in - self.middle * temp

    def __repr__(self):
        return "Active Function : Softmax"

class Tanh:
    def __init__(self):
        self.middle = None

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

    def forward(self, x):
        x = x - np.max(x, axis=1, keepdims=True)
        self.middle = (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
        return self.middle

    def backward(self, grad_in):
        return grad_in * (1 - self.middle ** 2)

    def __repr__(self):
        return "Active Function : Tanh"