from math import isclose

import numpy as np
import pytest

import src.matrix_operations as matops
from tests.utils import create_matrix

def test_add(name, data, exception):
    inp_matA = create_matrix(data.input.matA)
    inp_matB = create_matrix(data.input.matB)

    with exception:
        act = matops.add(inp_matA, inp_matB)

        exp = create_matrix(data.expect.mat)

        assert matops.almost_equal(act, exp)

def test_count_columns(name, data, exception):
    inp = create_matrix(getattr(data.input, "mat", None))

    with exception:
        act = matops.count_columns(inp)

        exp = data.expect

        assert act == exp

def test_count_rows(name, data, exception):
    inp = create_matrix(getattr(data.input, "mat", None))

    with exception:
        act = matops.count_rows(inp)

        exp = data.expect

        assert act == exp

def test_create_augmented(name, data, exception):
    inp_matA = create_matrix(data.input.A)
    inp_matb = create_matrix(data.input.b)
    orig_matA = matops.deepcopy(inp_matA)
    orig_matb = matops.deepcopy(inp_matb)

    with exception:
        act = matops.create_augmented(inp_matA, inp_matb)

        exp = create_matrix(data.expect)

        assert matops.almost_equal(act, exp)
        assert inp_matA.shape == orig_matA.shape
        assert inp_matb.shape == orig_matb.shape

def test_create_based_on_diagonal_terms(name, data, exception):
    inp = create_matrix(data.input.mat)

    with exception:
        act = matops.create_based_on_diagonal_terms(inp)

        exp = create_matrix(data.expect)

        assert matops.almost_equal(act, exp)

def test_create_based_on_l_component(name, data, exception):
    inp = create_matrix(data.input.mat)

    with exception:
        act = matops.create_based_on_l_component(inp)

        exp = create_matrix(data.expect.mat)

        assert matops.almost_equal(act, exp)

def test_create_based_on_non_diagonal_terms(name, data, exception):
    inp = create_matrix(data.input.mat)

    with exception:
        act = matops.create_based_on_non_diagonal_terms(inp)

        exp = create_matrix(data.expect)

        assert matops.almost_equal(act, exp)

def test_create_based_on_u_component(name, data, exception):
    inp_mat = create_matrix(data.input.mat)
    inp_diag_zero = data.input.diag_zero

    with exception:
        act = matops.create_based_on_u_component(inp_mat, inp_diag_zero)

        exp = create_matrix(data.expect.mat)

        assert matops.almost_equal(act, exp)

def test_create_identity(name, data, exception):
    inp = data.input

    with exception:
        act = matops.create_identity(inp)

        exp = create_matrix(data.expect)

        assert matops.almost_equal(act, exp)

def test_create_inverted(name, data, exception):
    inp = create_matrix(data.input.mat)

    with exception:
        act = matops.create_inverted(inp)

        exp = create_matrix(data.expect)

        assert matops.almost_equal(act, exp)

def test_create_ones(name, data, exception):
    inp_cols = data.input.columns
    inp_rows = data.input.rows

    with exception:
        act = matops.create_ones(inp_rows, inp_cols)

        exp = create_matrix(data.expect.mat)

        assert act.shape == exp.shape
        assert matops.almost_equal(act, exp)

def test_create_random(name, data, exception):
    inp_single_column = data.input.single_column
    inp_size = data.input.size

    with exception:
        act = matops.create_random(inp_size, inp_single_column)

        exp_columns = data.expect.columns
        exp_rows = data.expect.rows

        assert act.shape == (exp_rows, exp_columns)

def test_create_random_diag_dominate(name, data, exception):
    inp_size = data.input.size

    with exception:
        act = matops.create_random_diagonal_dominate(inp_size)

        exp_size = data.expect.size

        assert act.shape == (exp_size, exp_size)

        diag = act.diagonal()
        bigs = act.max(1)

        print(act)
        assert matops.almost_equal(diag, bigs)

def test_create_random_validate_values(name, data, exception):
    inp_single_column = data.input.single_column
    inp_size = data.input.size

    with exception:
        act = matops.create_random(inp_size, inp_single_column)

        assert act.dtype == np.float64

        mask = np.logical_and(act <= data.expect.upper, act >= data.expect.lower)
        act_all = np.all(mask)

        # All values should be within the expected range
        assert act_all != data.expect.any

def test_create_zeros(name, data, exception):
    inp_cols = data.input.columns
    inp_rows = data.input.rows

    with exception:
        act = matops.create_zeros(inp_rows, inp_cols)

        exp = create_matrix(data.expect.mat)

        assert act.shape == exp.shape
        assert matops.almost_equal(act, exp)

def test_is_augmented(name, data, exception):
    inp = create_matrix(data.input)

    with exception:
        act = matops.is_augmented(inp)

        assert act == data.expect

def test_is_hvector(name, data, exception):
    inp_as_raw = data.input.as_raw
    inp_value = data.input.value if inp_as_raw else create_matrix(data.input.value)

    with exception:
        act = matops.is_hvector(inp_value)

        exp = data.expect

        assert act == exp

def test_is_in_crout_l_form(name, data, exception):
    inp = create_matrix(data.input)

    with exception:
        act = matops.is_in_crout_l_form(inp)

        exp = data.expect

        assert act == exp

def test_is_in_reduced_row_echelon(name, data, exception):
    inp = create_matrix(data.input)

    with exception:
        act = matops.is_in_reduced_row_echelon(inp)

        assert act == data.expect

def test_is_matrix(name, data, exception):
    inp_as_raw = data.input.as_raw
    inp_value = data.input.value if inp_as_raw else create_matrix(data.input.value)

    with exception:
        act = matops.is_matrix(inp_value)

        exp = data.expect

        assert act == exp

def test_is_singular(name, data, exception):
    # print('')
    # print(data.name)
    inp = create_matrix(data.input)

    with exception:
        act = matops.is_singular(inp)

        assert act == data.expect

def test_is_square(name, data, exception):
    inp = create_matrix(data.input)

    with exception:
        act = matops.is_square(inp)

        assert act == data.expect

def test_is_vector(name, data, exception):
    inp_as_raw = data.input.as_raw
    inp_value = data.input.value if inp_as_raw else create_matrix(data.input.value)

    with exception:
        act = matops.is_vector(inp_value)

        exp = data.expect

        assert act == exp

def test_is_vvector(name, data, exception):
    inp_as_raw = data.input.as_raw
    inp_value = data.input.value if inp_as_raw else create_matrix(data.input.value)

    with exception:
        act = matops.is_vvector(inp_value)

        exp = data.expect

        assert act == exp

def test_multiply(name, data, exception):
    inp_matA = create_matrix(data.input.a)
    inp_b = data.input.b
    if isinstance(inp_b, list):
        inp_b = create_matrix(inp_b)

    with exception:
        act = matops.multiply(inp_matA, inp_b)

        exp = create_matrix(data.expect)

        assert matops.almost_equal(act, exp)

def test_multiply_row_by_scalar(name, data, exception):
    # print('')
    # print(data.name)
    inp_inplace = data.input.inplace
    inp_mat = create_matrix(data.input.mat)
    inp_row = data.input.row
    inp_scalar = data.input.scalar

    with exception:
        act = matops.multiply_row_by_scalar(inp_mat, inp_row, inp_scalar, inp_inplace)

        exp = create_matrix(data.expect.mat)

        # print(inp)
        # print(exp)
        # print(act)

        assert matops.almost_equal(act, exp)
        # make sure inp matrix was not mutated
        assert matops.almost_equal(act, inp_mat) == data.expect.inp_match_act

def test_percent_error(name, data, exception):
    # print('')
    # print(data.name)
    inp_act = create_matrix(data.input.act).reshape(-1, 1)
    inp_exp = create_matrix(data.input.exp).reshape(-1, 1)

    with exception:
        act = matops.percent_error(inp_act, inp_exp)

        exp = data.expect if data.expect != "np.inf" else np.inf

        # print(exp)
        # print(act)

        assert act >= 0.0
        assert isclose(act, exp, abs_tol=0.000_01)

def test_reshape(name, data, exception):
    inp_mat = create_matrix(data.input.mat)
    inp_newshape = (
        tuple(data.input.newshape.value)
        if data.input.newshape.as_tuple
        else data.input.newshape.value
    )

    with exception:
        act = matops.reshape(inp_mat, inp_newshape)

        exp = create_matrix(data.expect.mat)

        assert matops.almost_equal(act, exp)

def test_set_row_diagonal_to_one(name, data, exception):
    inp_inplace = data.input.inplace
    inp_mat = create_matrix(data.input.mat)
    inp_row = data.input.row

    with exception:
        act = matops.set_row_diagonal_to_one(inp_mat, inp_row, inp_inplace)

        exp = create_matrix(data.expect.mat)

        # print('')
        # print(data.name)
        # print(inp)
        # print(exp)
        # print(act)

        assert matops.almost_equal(act, exp)
        # make sure inp matrix was not mutated
        assert matops.almost_equal(act, inp_mat) == data.expect.inp_match_act

def test_set_rows_below_to_zero(name, data, exception):
    inp_inplace = data.input.inplace
    inp_mat = create_matrix(data.input.mat)
    inp_row = data.input.source_row

    with exception:
        act = matops.set_rows_below_to_zero(inp_mat, inp_row, inp_inplace)

        exp = create_matrix(data.expect.mat)

        assert matops.almost_equal(act, exp)
        # make sure inp matrix was not mutated
        assert matops.almost_equal(act, inp_mat) == data.expect.inp_match_act

def test_subtract(name, data, exception):
    inp_mat1 = create_matrix(data.input.mat1)
    inp_mat2 = create_matrix(data.input.mat2)

    with exception:
        act = matops.subtract(inp_mat1, inp_mat2)

        exp = create_matrix(data.expect.mat)

        assert matops.almost_equal(act, exp)

def test_subtract_scalar_row_from_row(name, data, exception):
    inp_inplace = data.input.inplace
    inp_mat = create_matrix(data.input.mat)
    inp_aff_row = data.input.affect_row
    inp_src_row = data.input.source_row

    with exception:
        act = matops.subtract_scalar_row_from_row(
            inp_mat, inp_src_row, inp_aff_row, inp_inplace
        )

        exp = create_matrix(data.expect.mat)

        # print('')
        # print(inp)
        # print(exp)
        # print(act)

        assert matops.almost_equal(act, exp)
        # make sure inp matrix was not mutated
        assert matops.almost_equal(act, inp_mat) == data.expect.inp_match_act

def test_swap_largest_pivot_to_top(name, data, exception):
    inp_inplace = data.input.inplace
    inp_mat = create_matrix(data.input.mat)
    inp_pivot = data.input.pivot

    with exception:
        act = matops.swap_largest_pivot_to_top(inp_mat, inp_pivot, inp_inplace)

        exp = create_matrix(data.expect.mat)

        # print('')
        # print(inp)
        # print(exp)
        # print(act)

        assert matops.almost_equal(act, exp)
        # make sure inp matrix was not mutated
        assert matops.almost_equal(act, inp_mat) == data.expect.inp_match_act

def test_to_reduced_row_echelon(name, data, exception):
    inp = create_matrix(data.input)

    with exception:
        act = matops.to_reduced_row_echelon(inp)

        exp = create_matrix(data.expect)

        # print('')
        # print(inp)
        # print(exp)
        # print(act)

        assert matops.almost_equal(act, exp)

def test_two_norm_of_error(name, data, exception):
    inpA = create_matrix(data.input.matA)
    inpb = create_matrix(data.input.matb)
    inpx = create_matrix(data.input.matx)

    with exception:
        act = matops.two_norm_of_error(inpA, inpb, inpx)

        exp = data.expect

        assert isclose(act, exp, abs_tol=0.000_01)


import sys
import numpy as np
# Thanks to https://stackoverflow.com/questions/49936222/an-efficient-sieve-of-eratosthenes-in-python
# for the optimizations to sieve

def sieve(n):
    primes = np.ones(n, dtype=bool)
    primes[0], primes[1] = False, False
    for i in range(2, int(np.sqrt(n) + 1)):
        if primes[i]:
            # Vectorization of the assignment operation (Uses a loop in C)
            primes[i*i::i] = False
    return np.flatnonzero(primes)

if __name__ == "__main__":
    sieve(int(sys.argv[1]))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CS231n Convolutional Neural Networks for Visual Recognition
http://cs231n.github.io/

Python Numpy Tutorial
http://cs231n.github.io/python-numpy-tutorial/

Numpy Reference
https://docs.scipy.org/doc/numpy/reference/
￣
python_numpy_tutorial-numpy_array_math.py
2019-07-02 (Tue)
"""
# Python Numpy Tutorial > Numpy > Array Math
#   Basic math functions operate elementwise on arrays.
#   In the numpy module, they're available both as
#     operator overloads and as functions.
#
# This examples cover:
#   Basic Math Functions
#     Elementwise sum         x+y or np.add(x,y)
#     Elementwise subtraction x-y or np.subtract(x,y)
#     Elementwise product     x*y or np.multiply(x,y)
#     Elementwise division    x/y or np.divide(x,y)
#     Elementwise square root        np.sqrt(x)
#   Inner Product 'dot
#     Inner product of vectors
#     Matrix-vector product
#     Matrix-matrix product
#     sum (as an example of math functions in numpy)
#
# Read more about:
#   numpy's full list of math functions
#     Mathematical functions
#     https://docs.scipy.org/doc/numpy/reference/routines.math.html
#   array manipulation routines
#     Array manipulation routines
#     https://docs.scipy.org/doc/numpy/reference/routines.array-manipulation.html

import numpy as np

##########################
#  Basic Math Functions  #
##########################

x = np.array( [[1,2],[3,4]], dtype=np.float64 )
y = np.array( [[5,6],[7,8]], dtype=np.float64 )
print( x )
#[[1. 2.]
# [3. 4.]]

print( y )
#[[5. 6.]
# [7. 8.]]

# Elementwise sum
print( x+y )
#[[ 6.  8.]
# [10. 12.]]

print( np.add(x,y) )
#[[ 6.  8.]
# [10. 12.]]

# Elementwise subtraction
print( x-y )
#[[-4. -4.]
# [-4. -4.]]

print( np.subtract(x,y) )
#[[-4. -4.]
# [-4. -4.]]

# Elementwise product
print( x*y )
#[[ 5. 12.]
# [21. 32.]]

print( np.multiply(x,y) )
#[[ 5. 12.]
# [21. 32.]]

# Elementwise division
print( x/y )
#[[0.2        0.33333333]
# [0.42857143 0.5       ]]

print( np.divide(x,y) )
#[[0.2        0.33333333]
# [0.42857143 0.5       ]]

# Elementwise square root
print( np.sqrt(x) )
#[[1.         1.41421356]
# [1.73205081 2.        ]]

#########################
#  Inner Product 'dot'  #
#########################
# Unlike MATLAB, * is elementwise multiplication,
#   not matrix multiplication.
# Instead, the dot function is used to compute
#   inner products of vectors,
#   to multiply a vector by a matrix, and
#   to multiply matrices.
# Dot is available both
#   as a function in the numpy module and
#   as an instance method of array objects.

x = np.array( [[1,2],[3,4]]  )
print(x, x.shape)
#[[1 2]
# [3 4]] (2, 2)

y = np.array( [[5,6],[7,8]] )
print(y, y.shape)
#[[5 6]
# [7 8]] (2, 2)

v = np.array( [9,10] )
print(v, v.shape)
#[ 9 10] (2,)

w = np.array( [11,12] )
print(w, w.shape)
#[11 12] (2,)

# Inner product of vectors
print( v.dot(w) )
# 219
# [9 10] [11 12] = 9*11+10*12 = 99 + 120 = 219

print( np.dot(v,w) )
# 219

# Matrix-vector product
#   x v = (2x2) x (2x1) = (2x1)
#   rank 1 array is procuded.
print( x.dot(v) )
# [29 67]

print( np.dot(x,v) )
# [29 67]

# Matrix-matrix product
#   produce rank 2 array.
print( x.dot(y) )
#[[19 22]
# [43 50]]

print( np.dot(x,y) )
#[[19 22]
# [43 50]]

#####################################
# NOTE: numpy math functions 'sum'  #
#####################################

x = np.array( [[1,2],[3,4]] )  # NOTE
print(x)                       # NOTE
#[[1 2]                        # NOTE
# [3 4]]                       # NOTE

print( np.sum(x) )             # All elements
#10

print( np.sum(x,axis=0) )      # Each column # NOTE
#[4 6]                         # NOTE

print( np.sum(x,axis=1) )      # Each row # NOTE
# [3 7]                        # NOTE

##########################
#  Transposing a matrix  #
##########################

x = np.array( [[1,2],[3,4]]  )
print(x)
#[[1 2]
# [3 4]]

print(x.T)
#[[1 3]
# [2 4]]

# NOTE: Taking the transpose of a rank 1 array DOES NOTHING!
v = np.array([1,2,3])  # NOTE
print(v, v.shape)      # NOTE
#[1 2 3] (3,)          # NOTE

print(v.T, v.T.shape)  # NOTE
#[1 2 3] (3,)          # NOTE


###############################################################################
#                                                                             #
#                         the_8_queen_solver.py                               #
#                                                                             #
###############################################################################
# Author:  Joao Nuno Carvalho                                                 #
# Data:    2019.12.27                                                         #
# License: MIT Open Source License                                            #
#                                                                             #
# Description: This is a Python program to solve the 8 Queen problem puzzle   #
#              using the BackTracking algorithm or strategy.                  #
#              The BackTracking algorithm is a way of solving constrained     #
#              satisfiable problems using recursion in a deep first tree      #
# traversal, in witch the solution is found iteratively. When the constrains  #
# aren't satisfied the solution step is backtracked, and from that comes it's #
# name. It founds the first solution and exits.                               #
# It can solve in a fast way even for 20 queens on a 20x20 chess board.       #
# Any Backtracking problem has:                                               #
#    -Choices                                                                 #
#    -Constrains                                                              #
#    -Goals                                                                   #
#                                                                             #
# To Run this code do:                                                        #
#                      Python the_8_queen_solver.py                           #
#                                                                             #
# For references see the project page at:                                     #
#     https://github.com/joaocarvalhoopen?tab=repositories                    #
###############################################################################

import numpy as np

MAX_NUM_ROWS = 8 # 20
MAX_NUM_COLS = 8 # 20

def printBoard(state, message):
    print("\n" + message + "\n")
    for row in range(0, MAX_NUM_ROWS):
        for col in range(0, MAX_NUM_COLS):
            print(state[row][col], end='')
            if col == MAX_NUM_COLS-1:
                print()
            else:
                print(" ", end='')

def isBoardStateConstrainsSatisfied(row_in, col_in, state):
    # Check the constrains.
    # Because we are building the solution iteratively, and the previous boards with
    # the previous placed queens are correct and not attacking each other, we only
    # need to check if there is a queen:
    #   -in the some row,
    #   -in the same column,
    #   -and in a diagonal of our current position.

    # Check row.
    for col in range(0, MAX_NUM_COLS):
        if col == col_in:
            continue
        if state[row_in][col] == 1:
            return False

    # Check column.
    for row in range(0, MAX_NUM_ROWS):
        if row == row_in:
            continue
        if state[row][col_in] == 1:
            return False

    # Check diagonals upper left.
    row = row_in
    col = col_in
    while (True):
        row -= 1
        col -= 1
        if row >= 0 and col >= 0:
            if state[row, col] == 1:
                return False
        else:
            break

    # Check diagonals upper right.
    row = row_in
    col = col_in
    while (True):
        row -= 1
        col += 1
        if row >= 0 and col < MAX_NUM_COLS:
            if state[row, col] == 1:
                return False
        else:
            break

    # Check diagonals down left.
    row = row_in
    col = col_in
    while (True):
        row += 1
        col -= 1
        if row < MAX_NUM_ROWS and col >= 0:
            if state[row, col] == 1:
                return False
        else:
            break

    # Check diagonals down right.
    row = row_in
    col = col_in
    while (True):
        row += 1
        col += 1
        if row < MAX_NUM_ROWS and col < MAX_NUM_COLS:
            if state[row, col] == 1:
                return False
        else:
            break

    # NOTE: We can implement in a simpler way, testing all board position, it can
    #       also work for a small board of 8x8, but that would not work but a bigger board.
    #
    #for row in range(0, MAX_NUM_ROWS):
    #    for col in range(0, MAX_NUM_COLS):
    #        rowDiff = row - row_in
    #        colDiff = col - col_in
    #        if not (row == row_in and col == col_in) and
    #           (row == row_in or col == col_in or rowDiff == colDiff))
    #           if state[row][col]] == 1:
    #               return False

    return True

def solve(row_in, col_in, state):
    # Establish the stopping GOAL.
    if row_in >= MAX_NUM_ROWS:
        return state.copy()

    # Give all the CHOICES to experiment incrementally.
    newState = state.copy()
    for choice in range(0, MAX_NUM_COLS):
        col = choice
        newState[row_in, col] = 1
        # Validate choice against CONSTRAINS.
        if not isBoardStateConstrainsSatisfied(row_in, col, newState):
            # Removes the previous choice.
            newState[row_in, col] = 0
            continue
        # if valid, incrementally build the next solution phase.
        foundSolutionBoard = solve(row_in + 1, col, newState)
        if type(foundSolutionBoard) != type(False):
            # Achieved the GOAL.
            return foundSolutionBoard
        # Removes the previous choice.
        newState[row_in, col] = 0
    return False

if __name__ == "__main__":
    print("\n#############################")
    print(  "# The 8 Queen Puzzle Solver #")
    print(  "#############################")

    board = np.zeros((MAX_NUM_ROWS, MAX_NUM_COLS), dtype='int')
    printBoard(board, "Puzzle board...")
    row = 0
    col = 0
    foundSolutionBoard = solve(row, col, board)
    printBoard(foundSolutionBoard, "Solution...")


import numpy as nmp
from CodeEntropy.FunctionCollection import CustomFunctions as CF

def transform_coordinates(arg_origVector, arg_oldBase, arg_newBase):
	"""Given a 3D vector (origVector; V) with components in the old_base (3,3 matrix),
	transform it to a new 3D vector (return value) with components in the new_base (3x3 matrix).
	A 3X3 transformation matrix TM is created which gives new vector components V' = TM @ V.
	TM[i,j] = dot(axis{j_new}, axis{i_old}).

	NOTE: Axes in both coordinate system have to be orthogonal"""

	#transformation matrix
	TM = [[nmp.dot(j,i) for i in arg_newBase] for j in arg_oldBase]

	return TM @ arg_origVector

#END

def get_cartesian_midpoint3D(arg_point1, arg_point2):
	""" Get the cartesian midpoint of the line joining two 3D points """
	return nmp.multiply(0.5, nmp.add(arg_point1, arg_point2))

#END

def generate_orthonormal_axes_system(arg_coord1, arg_coord2, arg_coord3):
	"""Generate a 3 x 3 matrix with columns as axes of the returning coordinate system.
	They must be orthonormal (assert).
	Axis 1: Along the C-N line, from altitude bisector to C
	Axis 2: from altitde bisecting point of C-N to Ca
	Axis 3: Cross of Axis1 and Axis 2

	Return the basis and the origin"""

	basis = nmp.ndarray((3,3))

	r1 = arg_coord1
	r2 = arg_coord2
	r3 = arg_coord3

	r31 = r3 - r1
	r21 = r2 - r1

	#derived formula
	rAltitude = nmp.dot(r31, r21) * r21
	rAltitude /= nmp.linalg.norm(r21)**2
	rAltitude += r1

	# Axis 0
	axis0 = r2 - rAltitude
	axis0 /= nmp.linalg.norm(axis0)
	basis[0,:] = axis0

	# Axis 1
	axis1 = r3 - rAltitude
	axis1 /= nmp.linalg.norm(axis1)
	basis[1,:] = axis1

	# Axis 2
	# axis2 = nmp.cross(axis0, axis1)
	axis2 = CF.cross_product(axis0, axis1)
	axis2 /= nmp.linalg.norm(axis2)
	basis[2,:] = axis2

	# due to FP limitations, the check will verly likely fail
	# assert(nmp.dot(axis1, axis2) == 0)

	return basis, rAltitude

#END

def get_altitude(arg_lineEndPoint1, arg_lineEndPoint2, arg_sourcePoint):
	"""
	For the three points in the input,
	2 form a line segement and
	the thrid one is the point from
	where the altitude on the line segement is computed.

	Returns te altitude vector"""

	r1 = arg_lineEndPoint1
	r2 = arg_lineEndPoint2
	r3 = arg_sourcePoint

	r31 = r3 - r1
	r21 = r2 - r1

	#derived formula
	rAltitude = nmp.dot(r31, r21) * r21
	rAltitude /= nmp.linalg.norm(r21)**2
	rAltitude = r31 - rAltitude

	return rAltitude

# END

def get_sphCoord_axes(arg_r):
	""" For a given vector in space, treat it is a radial vector rooted at 0,0,0 and
	derive a curvilinear coordinate system according to the rules of polar spherical
	coordinates"""

	x2y2 = arg_r[0]**2 + arg_r[1]**2
	r2 = x2y2 + arg_r[2]**2

	if x2y2 != 0.:
		sinTheta = nmp.sqrt(x2y2/r2)
		cosTheta = arg_r[2]/nmp.sqrt(r2)

		sinPhi = arg_r[1]/nmp.sqrt(x2y2)
		cosPhi = arg_r[0]/nmp.sqrt(x2y2)

	else:
		sinTheta = 0.
		cosTheta = 1

		sinPhi = 0.
		cosPhi = 1

	# if abs(sinTheta) > 1 or abs(sinPhi) > 1:
	#	 print('Bad sine : T {} , P {}'.format(sinTheta, sinPhi))

	# cosTheta = nmp.sqrt(1 - sinTheta*sinTheta)
	# cosPhi = nmp.sqrt(1 - sinPhi*sinPhi)

	# print('{} {} {}'.format(*arg_r))
	# print('Sin T : {}, cos T : {}'.format(sinTheta, cosTheta))
	# print('Sin P : {}, cos P : {}'.format(sinPhi, cosPhi))

	sphericalBasis = nmp.zeros((3,3))

	# r^
	sphericalBasis[0,:] = nmp.asarray([sinTheta*cosPhi, sinTheta*sinPhi, cosTheta])

	# Theta^
	sphericalBasis[1,:] = nmp.asarray([cosTheta*cosPhi, cosTheta*sinPhi, -sinTheta])

	# Phi^
	sphericalBasis[2,:] = nmp.asarray([-sinPhi, cosPhi, 0.])

	return sphericalBasis

# END

def compute_dihedral(arg_ri, arg_rj, arg_rk, arg_rl):
	"""
	Return the dihedral angle in degrees formed by the atoms with the input coordinates.
	The formula to compute was obtained from:
	https://www.math.fsu.edu/~quine/MB_10/6_torsion.pdf

	"""

	# define the directed line segments (vectors)
	a = nmp.subtract(arg_rj, arg_ri) # i->j
	b = nmp.subtract(arg_rk, arg_rj) # j->k
	c = nmp.subtract(arg_rl, arg_rk) # k->l

	# Complex number formalism for finding the angle
	# Z = X + jY
	X = -nmp.dot(a,c) * nmp.dot(b,b)
	X += ( nmp.dot(a,b) * nmp.dot(b,c) )

	Y = nmp.dot(a, nmp.cross(b,c))
	Y *= nmp.linalg.norm(b)

	# dihedral angle (in degrees)
	dih = nmp.angle(complex(X,Y), deg=True)

	return dih
# END


# coding=utf-8
"""
Bezier Surface using python, numpy and matplotlib.
"""

import numpy as np
import matplotlib.pyplot as mpl

__author__ = "Daniel Calderon"
__license__ = "MIT"

def generateT(t):
    return np.array([[1, t, t ** 2, t ** 3]]).T

def evalBernstein3(k, t):
    # Full Bezier Matrix
    Mb = np.array([[1, -3, 3, -1], [0, 3, -6, 3], [0, 0, 3, -3], [0, 0, 0, 1]])

    T = generateT(t)

    return np.dot(Mb[k, :], T)[0]

def evalBezierSurfaceSample(ps, t, s):
    Q = np.zeros(3)
    for k in range(4):
        for l in range(4):
            Bk = evalBernstein3(k, s)
            Bl = evalBernstein3(l, t)

            Q += Bk * Bl * ps[k, l]

    return Q

def evalBezierSurface(ps, ts, ss):
    Q = np.ndarray(shape=(N, N, 3), dtype=float)
    for i in range(len(ts)):
        for j in range(len(ss)):
            Q[i, j] = evalBezierSurfaceSample(ps, ts[i], ss[j])

    return Q

if __name__ == "__main__":
    """
    Defining control points
    """

    # A 4x4 array with a control point in each of those positions
    P = np.ndarray(shape=(4, 4, 3), dtype=float)
    P[0, 0, :] = np.array([[0, 0, 0]])
    P[0, 1, :] = np.array([[0, 1, 0]])
    P[0, 2, :] = np.array([[0, 2, 0]])
    P[0, 3, :] = np.array([[0, 3, 0]])

    P[1, 0, :] = np.array([[1, 0, 0]])
    P[1, 1, :] = np.array([[1, 1, 10]])
    P[1, 2, :] = np.array([[1, 2, 10]])
    P[1, 3, :] = np.array([[1, 3, 0]])

    P[2, 0, :] = np.array([[2, 0, 0]])
    P[2, 1, :] = np.array([[2, 1, 10]])
    P[2, 2, :] = np.array([[2, 2, 10]])
    P[2, 3, :] = np.array([[2, 3, 0]])

    P[3, 0, :] = np.array([[3, 0, 0]])
    P[3, 1, :] = np.array([[3, 1, -5]])
    P[3, 2, :] = np.array([[3, 2, -5]])
    P[3, 3, :] = np.array([[3, 3, 0]])

    # Setting up the matplotlib display for 3D
    fig = mpl.figure()
    ax = fig.gca(projection='3d')

    """
    Visualizing the control points
    """
    # They are sorted into a list of points
    Pl = P.reshape(16, 3)

    # Each component is queried from the previous array
    ax.scatter(Pl[:, 0], Pl[:, 1], Pl[:, 2], color=(1, 0, 0), label="Control Points")

    """
    Discretizing the surface
    """
    # We use the same amount of samples for both, t and s parameters
    N = 10

    # The parameters t and s should move between 0 and 1
    ts = np.linspace(0.0, 1.0, N)
    ss = np.linspace(0.0, 1.0, N)

    # This function evaluates the bezier surface at each t and s samples in the arrays
    # The solution is stored in the 2D-array Q, where each sample is a 3D vector
    Q = evalBezierSurface(P, ts, ss)

    """
    Visualizing the Bezier surface
    """
    # For convenience, we re-organize the data into a list of points
    QlinearShape = (Q.shape[0] * Q.shape[1], 3)
    Ql = Q.reshape(QlinearShape)

    # An option is to plot just each dot computed
    # ax.scatter(Ql[:,0], Ql[:,1], Ql[:,2], color=(0,0,1))

    # The more elegant option is to make a triangulation and visualize it as a surface
    surf = ax.plot_trisurf(Ql[:, 0], Ql[:, 1], Ql[:, 2], linewidth=0, antialiased=False)

    # Showing the result
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    ax.legend()
    mpl.title("Bezier Surface")
    mpl.show()


import numpy as np
from collections import Counter

from dbca.freq_distribution import FrequencyDistribution

def chernoff_similarity(P: FrequencyDistribution, Q: FrequencyDistribution, alpha: float = 0.5) -> float:
    """
    Return Chernoff similarity between 2 frequency distributions

    Parameters
    ----------
    P : FrequencyDistribution
    Q : FrequencyDistribution
    alpha: float
        Chernoff co-efficient (scalar in [0,1])

    Returns
    -------
    float
        Chernoff similarity.

    """
    all_elements = sorted(list(P.elements | Q.elements)) # ensure same iteration order
    p_probs = np.array([P.element_prob(e) for e in all_elements])**alpha
    q_probs = np.array([Q.element_prob(e) for e in all_elements])**(1-alpha)
    return np.dot(p_probs, q_probs)

def chernoff_divergence(P: FrequencyDistribution, Q: FrequencyDistribution, alpha: float = 0.5) -> float:
    """
    Return complement of Chernoff similarity between two distributions

    Parameters
    ----------
    P : FrequencyDistribution
    Q : FrequencyDistribution
    alpha : float, optional
        Chernoff co-efficient. The default is 0.5.

    Returns
    -------
    float
        DESCRIPTION.

    """
    return 1 - chernoff_similarity(P, Q, alpha)


#!/usr/bin/env python
# As v1, but using scipy.sparse.diags instead of spdiags
"""
Functions for solving a 1D diffusion equations of simplest types
(constant coefficient, no source term):

      u_t = a*u_xx on (0,L)

with boundary conditions u=0 on x=0,L, for t in (0,T].
Initial condition: u(x,0)=I(x).

The following naming convention of variables are used.

===== ==========================================================
Name  Description
===== ==========================================================
Nx    The total number of mesh cells; mesh points are numbered
      from 0 to Nx.
F     The dimensionless number a*dt/dx**2, which implicitly
      specifies the time step.
T     The stop time for the simulation.
I     Initial condition (Python function of x).
a     Variable coefficient (constant).
L     Length of the domain ([0,L]).
x     Mesh points in space.
t     Mesh points in time.
n     Index counter in time.
u     Unknown at current/new time level.
u_n   u at the previous time level.
dx    Constant mesh spacing in x.
dt    Constant mesh spacing in t.
===== ==========================================================

user_action is a function of (u, x, t, n), u[i] is the solution at
spatial mesh point x[i] at time t[n], where the calling code
can add visualization, error computations, data analysis,
store solutions, etc.
"""
import sys
import time
# import scitools.std as plt
import scipy.sparse
import scipy.sparse.linalg
import numpy as np

def solver_FE_simple(I, a, f, L, dt, F, T):
    """
    Simplest expression of the computational algorithm
    using the Forward Euler method and explicit Python loops.
    For this method F <= 0.5 for stability.
    """
    import time
    t0 = time.perf_counter()  # For measuring the CPU time

    Nt = int(round(T/float(dt)))
    t = np.linspace(0, Nt*dt, Nt+1)   # Mesh points in time
    dx = np.sqrt(a*dt/F)
    Nx = int(round(L/dx))
    x = np.linspace(0, L, Nx+1)       # Mesh points in space
    # Make sure dx and dt are compatible with x and t
    dx = x[1] - x[0]
    dt = t[1] - t[0]

    u = np.zeros(Nx+1)
    u_n = np.zeros(Nx+1)

    # Set initial condition u(x,0) = I(x)
    for i in range(0, Nx+1):
        u_n[i] = I(x[i])

    for n in range(0, Nt):
        # Compute u at inner mesh points
        for i in range(1, Nx):
            u[i] = u_n[i] + F*(u_n[i-1] - 2*u_n[i] + u_n[i+1]) + \
                   dt*f(x[i], t[n])

        # Insert boundary conditions
        u[0] = 0
        u[Nx] = 0

        # Switch variables before next step
        # u_n[:] = u  # safe, but slow
        u_n, u = u, u_n

    t1 = time.perf_counter()
    return u_n, x, t, t1-t0  # u_n holds latest u

def solver_FE(I, a, f, L, dt, F, T,
              user_action=None, version='scalar'):
    """
    Vectorized implementation of solver_FE_simple.
    """
    t0 = time.perf_counter()  # for measuring the CPU time

    Nt = int(round(T/float(dt)))
    t = np.linspace(0, Nt*dt, Nt+1)   # Mesh points in time
    dx = np.sqrt(a*dt/F)
    Nx = int(round(L/dx))
    x = np.linspace(0, L, Nx+1)       # Mesh points in space
    # Make sure dx and dt are compatible with x and t
    dx = x[1] - x[0]
    dt = t[1] - t[0]

    u = np.zeros(Nx+1)  # solution array
    u_n = np.zeros(Nx+1)  # solution at t-dt

    # Set initial condition
    for i in range(0, Nx+1):
        u_n[i] = I(x[i])

    if user_action is not None:
        user_action(u_n, x, t, 0)

    for n in range(0, Nt):
        # Update all inner points
        if version == 'scalar':
            for i in range(1, Nx):
                u[i] = u_n[i] +\
                       F*(u_n[i-1] - 2*u_n[i] + u_n[i+1]) +\
                       dt*f(x[i], t[n])

        elif version == 'vectorized':
            u[1:Nx] = u_n[1:Nx] +  \
                      F*(u_n[0:Nx-1] - 2*u_n[1:Nx] + u_n[2:Nx+1]) +\
                      dt*f(x[1:Nx], t[n])
        else:
            raise ValueError('version=%s' % version)

        # Insert boundary conditions
        u[0] = 0
        u[Nx] = 0
        if user_action is not None:
            user_action(u, x, t, n+1)

        # Switch variables before next step
        u_n, u = u, u_n

    t1 = time.perf_counter()
    return t1-t0

def solver_BE_simple(I, a, f, L, dt, F, T, user_action=None):
    """
    Simplest expression of the computational algorithm
    for the Backward Euler method, using explicit Python loops
    and a dense matrix format for the coefficient matrix.
    """
    import time
    t0 = time.perf_counter()  # for measuring the CPU time

    Nt = int(round(T/float(dt)))
    t = np.linspace(0, Nt*dt, Nt+1)   # Mesh points in time
    dx = np.sqrt(a*dt/F)
    Nx = int(round(L/dx))
    x = np.linspace(0, L, Nx+1)       # Mesh points in space
    # Make sure dx and dt are compatible with x and t
    dx = x[1] - x[0]
    dt = t[1] - t[0]

    u = np.zeros(Nx+1)
    u_n = np.zeros(Nx+1)

    # Data structures for the linear system
    A = np.zeros((Nx+1, Nx+1))
    b = np.zeros(Nx+1)

    for i in range(1, Nx):
        A[i, i-1] = -F
        A[i, i+1] = -F
        A[i, i] = 1 + 2*F
    A[0, 0] = A[Nx, Nx] = 1

    # Set initial condition u(x,0) = I(x)
    for i in range(0, Nx+1):
        u_n[i] = I(x[i])
    if user_action is not None:
        user_action(u_n, x, t, 0)

    for n in range(0, Nt):
        # Compute b and solve linear system
        for i in range(1, Nx):
            b[i] = u_n[i] + dt*f(x[i], t[n+1])
        b[0] = b[Nx] = 0
        u[:] = np.linalg.solve(A, b)

        if user_action is not None:
            user_action(u, x, t, n+1)

        # Update u_n before next step
        u_n, u = u, u_n

    t1 = time.perf_counter()
    return t1-t0

def solver_BE(I, a, f, L, dt, F, T, user_action=None):
    """
    Vectorized implementation of solver_BE_simple using also
    a sparse (tridiagonal) matrix for efficiency.
    """
    import time
    t0 = time.perf_counter()  # for measuring the CPU time

    Nt = int(round(T/float(dt)))
    t = np.linspace(0, Nt*dt, Nt+1)   # Mesh points in time
    dx = np.sqrt(a*dt/F)
    Nx = int(round(L/dx))
    x = np.linspace(0, L, Nx+1)       # Mesh points in space
    # Make sure dx and dt are compatible with x and t
    dx = x[1] - x[0]
    dt = t[1] - t[0]

    u = np.zeros(Nx+1)  # Solution array at t[n+1]
    u_n = np.zeros(Nx+1)  # Solution at t[n]

    # Representation of sparse matrix and right-hand side
    diagonal = np.zeros(Nx+1)
    lower = np.zeros(Nx)
    upper = np.zeros(Nx)
    b = np.zeros(Nx+1)

    # Precompute sparse matrix
    diagonal[:] = 1 + 2*F
    lower[:] = -F  # 1
    upper[:] = -F  # 1
    # Insert boundary conditions
    diagonal[0] = 1
    upper[0] = 0
    diagonal[Nx] = 1
    lower[-1] = 0

    A = scipy.sparse.diags(
        diagonals=[diagonal, lower, upper],
        offsets=[0, -1, 1], shape=(Nx+1, Nx+1),
        format='csr')
    print(A.todense())

    # Set initial condition
    for i in range(0, Nx+1):
        u_n[i] = I(x[i])

    if user_action is not None:
        user_action(u_n, x, t, 0)

    for n in range(0, Nt):
        b = u_n + dt*f(x[:], t[n+1])
        b[0] = b[-1] = 0.0  # boundary conditions
        u[:] = scipy.sparse.linalg.spsolve(A, b)

        if user_action is not None:
            user_action(u, x, t, n+1)

        # Update u_n before next step
        # u_n[:] = u
        u_n, u = u, u_n

    t1 = time.perf_counter()
    return t1-t0

def solver_theta(I, a, f, L, dt, F, T, theta=0.5, u_L=0, u_R=0,
                 user_action=None):
    """
    Full solver for the model problem using the theta-rule
    difference approximation in time (no restriction on F,
    i.e., the time step when theta >= 0.5).
    Vectorized implementation and sparse (tridiagonal)
    coefficient matrix.
    """
    import time
    t0 = time.perf_counter()  # for measuring the CPU time

    Nt = int(round(T/float(dt)))
    t = np.linspace(0, Nt*dt, Nt+1)   # Mesh points in time
    dx = np.sqrt(a*dt/F)
    Nx = int(round(L/dx))
    x = np.linspace(0, L, Nx+1)       # Mesh points in space
    # Make sure dx and dt are compatible with x and t
    dx = x[1] - x[0]
    dt = t[1] - t[0]

    u = np.zeros(Nx+1)   # solution array at t[n+1]
    u_n = np.zeros(Nx+1)   # solution at t[n]

    # Representation of sparse matrix and right-hand side
    diagonal = np.zeros(Nx+1)
    lower = np.zeros(Nx)
    upper = np.zeros(Nx)
    b = np.zeros(Nx+1)

    # Precompute sparse matrix (scipy format)
    Fl = F*theta
    Fr = F*(1-theta)
    diagonal[:] = 1 + 2*Fl
    lower[:] = -Fl  # 1
    upper[:] = -Fl  # 1
    # Insert boundary conditions
    diagonal[0] = 1
    upper[0] = 0
    diagonal[Nx] = 1
    lower[-1] = 0

    diags = [0, -1, 1]
    A = scipy.sparse.diags(
        diagonals=[diagonal, lower, upper],
        offsets=[0, -1, 1], shape=(Nx+1, Nx+1),
        format='csr')
    print(A.todense())

    # Set initial condition
    for i in range(0, Nx+1):
        u_n[i] = I(x[i])

    if user_action is not None:
        user_action(u_n, x, t, 0)

    # Time loop
    for n in range(0, Nt):
        b[1:-1] = u_n[1:-1] + \
                  Fr*(u_n[:-2] - 2*u_n[1:-1] + u_n[2:]) + \
                  dt*theta*f(x[1:-1], t[n+1]) + \
                  dt*(1-theta)*f(x[1:-1], t[n])
        b[0] = u_L  # Boundary conditions
        b[-1] = u_R
        u[:] = scipy.sparse.linalg.spsolve(A, b)

        if user_action is not None:
            user_action(u, x, t, n+1)

        # Update u_n before next step
        u_n, u = u, u_n

    t1 = time.perf_counter()
    return t1-t0

def viz(I, a, L, dt, F, T, umin, umax,
        scheme='FE', animate=True, framefiles=True):

    def plot_u(u, x, t, n):
        plt.plot(x, u, 'r-', axis=[0, L, umin, umax],
                 title='t=%f' % t[n])
        if framefiles:
            plt.savefig('tmp_frame%04d.png' % n)
        if t[n] == 0:
            time.sleep(2)
        elif not framefiles:
            # It takes time to write files so pause is needed
            # for screen only animation
            time.sleep(0.2)

    user_action = plot_u if animate else lambda u, x, t, n: None

    cpu = eval('solver_'+scheme)(I, a, L, dt, F, T,
                                 user_action=user_action)
    return cpu

def plug(scheme='FE', F=0.5, Nx=50):
    L = 1.
    a = 1.
    T = 0.1
    # Compute dt from Nx and F
    dx = L/Nx
    dt = F/a*dx**2

    def I(x):
        """Plug profile as initial condition."""
        if abs(x-L/2.0) > 0.1:
            return 0
        else:
            return 1

    cpu = viz(I, a, L, dt, F, T,
              umin=-0.1, umax=1.1,
              scheme=scheme, animate=True, framefiles=True)
    print('CPU time:', cpu)

def gaussian(scheme='FE', F=0.5, Nx=50, sigma=0.05):
    L = 1.
    a = 1.
    T = 0.1
    # Compute dt from Nx and F
    dx = L/Nx
    dt = F/a*dx**2

    def I(x):
        """Gaussian profile as initial condition."""
        return exp(-0.5*((x-L/2.0)**2)/sigma**2)

    u, cpu = viz(I, a, L, dt, F, T,
                 umin=-0.1, umax=1.1,
                 scheme=scheme, animate=True, framefiles=True)
    print('CPU time:', cpu)

def expsin(scheme='FE', F=0.5, m=3):
    L = 10.0
    a = 1
    T = 1.2

    def exact(x, t):
        return exp(-m**2*pi**2*a/L**2*t)*sin(m*pi/L*x)

    def I(x):
        return exact(x, 0)

    Nx = 80
    # Compute dt from Nx and F
    dx = L/Nx
    dt = F/a*dx**2
    viz(I, a, L, dt, F, T, -1, 1, scheme=scheme, animate=True,
        framefiles=True)

    # Convergence study
    def action(u, x, t, n):
        e = abs(u - exact(x, t[n])).max()
        errors.append(e)

    errors = []
    Nx_values = [10, 20, 40, 80, 160]
    for Nx in Nx_values:
        eval('solver_'+scheme)(I, a, L, Nx, F, T, user_action=action)
        dt = F*(L/Nx)**2/a
        print(dt, errors[-1])

def test_solvers():
    def u_exact(x, t):
        return x*(L-x)*5*t  # fulfills BC at x=0 and x=L

    def I(x):
        return u_exact(x, 0)

    def f(x, t):
        return 5*x*(L-x) + 10*a*t

    a = 3.5
    L = 1.5
    Nx = 4
    F = 0.5
    # Compute dt from Nx and F
    dx = L/Nx
    dt = F/a*dx**2

    def compare(u, x, t, n):      # user_action function
        """Compare exact and computed solution."""
        u_e = u_exact(x, t[n])
        diff = abs(u_e - u).max()
        tol = 1E-14
        assert diff < tol, 'max diff: %g' % diff

    import functools
    s = functools.partial  # object for calling a function w/args
    solvers = [
        s(solver_FE_simple, I=I, a=a, f=f, L=L, dt=dt, F=F, T=0.2),
        s(solver_FE, I=I, a=a, f=f, L=L, dt=dt, F=F, T=2,
          user_action=compare, version='scalar'),
        s(solver_FE, I=I, a=a, f=f, L=L, dt=dt, F=F, T=2,
          user_action=compare, version='vectorized'),
        s(solver_BE_simple, I=I, a=a, f=f, L=L, dt=dt, F=F, T=2,
          user_action=compare),
        s(solver_BE, I=I, a=a, f=f, L=L, dt=dt, F=F, T=2,
          user_action=compare),
        s(solver_theta, I=I, a=a, f=f, L=L, dt=dt, F=F, T=2,
          theta=0, u_L=0, u_R=0, user_action=compare),
        ]
    # solver_FE_simple has different return from the others
    u, x, t, cpu = solvers[0]()
    u_e = u_exact(x, t[-1])
    diff = abs(u_e - u).max()
    tol = 1E-14
    print(u_e)
    print(u)
    assert diff < tol, 'max diff solver_FE_simple: %g' % diff

    for solver in solvers:
        solver()

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("""Usage %s function arg1 arg2 arg3 ...""" % sys.argv[0])
        sys.exit(0)
    cmd = '%s(%s)' % (sys.argv[1], ', '.join(sys.argv[2:]))
    print(cmd)
    eval(cmd)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np

def linealSolverForward(A, b):
    """Solves a system of equations given a lower triangular matrix.

    Arguments:
        A: Lower triangular matrix. Shape: (n, n)
        b: System's solutions. Shape: (n, 1)

    Raises:
        RuntimeError if A is not lower triangular

    Returns:
        A numpy array with the system's X vector. Shape: (n, 1)
    """
    #First we check if the matrix is a lower triangle
    if np.allclose(A, np.tril(A)):
        n = len(b)
        x = np.zeros((n, 1))

        #we apply the forward formula for every element of x
        for k in range(0, n):
            tempSum = []
            for number in range(0, k):
                tempSum.append(-1 * A[k][number] * x[number])
            tempSum = sum(tempSum)
            x[k] = (b[k] + tempSum) / A[k][k]

        return x

    else:
        raise RuntimeError("Matrix A is not lower triangular.")

def test_linealSolverForward():
    """Test linealSolverForward.

    This function will stop the code execution when it finds an error.

    Returns:
        None
    """

    # ====== Forward and backwards substitution ======
    # Each tuple has tree elements, by index:
    # 0: matrix A (lower triangular)
    # 1: matrix b (System solution)
    # 2: matrix c (Expected answer)
    #
    # System's solutions were verified using WolframAlpha.

    lowTriangMatrices = (
        (np.array([[8, 0, 0], [2, 3, 0], [4, 7, 1]]),
         np.array([[8], [5], [0]]),
         np.array([[1], [1], [-11]])),
        (np.array([[8, 0, 0], [2, 3, 0], [4, 7, 1]]),
         np.array([[5], [1], [-8]]),
         np.array([[5 / 8], [-1 / 12], [-119 / 12]])),
        (np.array([[5, 0, 0], [76, 63, 0], [47, 77, 31]]),
         np.array([[69], [10], [4]]),
         np.array([[69 / 5], [-742 / 45], [28127 / 1395]])),
        (np.array([[44, 0, 0, 0], [17, 10, 0, 0],
                   [65, 43, 49, 0], [75, 5, 81, 76]]),
         np.array([[66], [74], [8], [22]]),
         np.array([[3 / 2], [97 / 20], [-5961 / 980], [9747 / 1960]])),
    )

    print("="*60, "\nTesting linearSolverForward() function.")
    for system in lowTriangMatrices:
        try:
            print('-'*50)
            print("Testing system:\n"
                  + f"A =\n{system[0]}\n"
                  + f"b =\n{system[1]}\n"
                  + f"Expected answer =\n{system[2]}")

            ans = linealSolverForward(system[0], system[1])
            comparison = np.allclose(ans, system[2])
            assert \
                    comparison, \
                    "The last tested system did not pass the test."
            print("-> Pass <-")
        except RuntimeError:
            assert False, "The last tested system did not pass the test."

if __name__ == "__main__":
    print("Executed as stand-alone script. Running test function.\n")
    test_linealSolverForward()


# Objective: Introduction to Numpy. Understanding it for data analysis
# Reference: https://www.machinelearningplus.com/python/numpy-tutorial-part1-array-python-examples/

import numpy as np

# There are many ways to create a numpy array. The most common one is to create a list and then pass it into `np.array()` function
list1=[1,2,3,4]
print("list and its type", type(list1))
arr1= np.array(list1)
print(type(arr1))

# A list cannot handle math operations while a numpy array can
#list1+2 will give error
print(arr1+2)

# create a 2d array
list2 = [[0,1,22],[3,4,5]]
print(list2)
print(np.array(list2))
# specify the datatype by setting the dtype argument
list2 = [[0,1,22],[3,4,5]]
print(np.array(list2, dtype=float)) # The decimal point after each number is indicative of the float datatype.

# You can also convert it to a different datatype using the astype method.
arr2d = np.array(list2)
print(arr2d.astype(str))

# if you are uncertain about what datatype your array will hold or if you want to hold characters and numbers in the same array, you can set the dtype as 'object'.
# create an array to hold numbers and strings
arr2d_obj = np.array([1,2.3,4.4,100,'cat','bat'], dtype=object)
print(arr2d_obj)

# Finally, you can always convert an array back to a python list using tolist().
print(arr2d_obj.tolist())

# How to check the array shape and size?
# In R, use dim() for dimesnions and shape()
# In Python use, ndim(), to check if its 1D or 2D array;
# In python use, shape(), to check how many items are present in each dimension.
# In python use, dtype(), to check the data type
# In python use, size(), to check the size of array
# In python use, shape(), to sample a first few items through indexing
print(arr2d.ndim)
print(arr2d_obj.shape)
print(arr2d_obj.dtype)
print(arr2d_obj.size)
#print(arr2d_obj.sample)

# How to extract specific elements from a numpy array. Use the : notation
list3 = [10,20,30,40]
arr2 = np.array(list3)
x = arr2[:4]
print(x)

# reverse the rows and the whole array. Use :: notation
print(arr2[::-1]) # reverse only the rows
list4 = [[1,2,3,4],[5,6,7,8]]
arr3 = np.array(list4, dtype=float)
print(arr3[::-1,::-1])

# Missing values can be represented using np.nan object, while np.inf represents infinite.
# Insert a nan and an inf
arr3[1,1] = np.nan  # not a number
arr3[1,2] = np.inf  # infinite
print(arr3)

# How to compute mean, min, max on the ndarray?
list5 = [[1,2,3,4],[5,6,7,8]]
arr4 = np.array(list5)
print("Mean value is ", arr4.mean())
print("Min value is ", arr4.min())
print("Max value is ", arr4.max())

# How to compute row-wise and col-wise mean? Use np.amin()
print("Row wise min is ", np.amin(arr4, axis=0))
print("Col wise min is ", np.amin(arr4, axis=1))


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 20 21:10:01 2018

@author: Thiago Almeida
"""

import matplotlib.pyplot as plt
import matplotlib.lines as mlines
import numpy as np
import math as m

#imports locais
from Utils import Utils
from interpoladores.Lagrange import Lagrange
from interpoladores.Linear import Linear
from interpoladores.Newton import Newton

#funcao exata
def F(x):
    #return m.cos(x)
    return 1.0 / (1.0 + 25.0 * x**2)

#gera pontos para letra A
def gerarPontos_a(a, b, n):
    xk = np.zeros((n+1,), dtype=np.float128)

    for k in range (0,n+1):
        xk[k] = a + ((b-a)*k)/n

    return xk

#gera pontos para letra B
def gerarPontos_b(a, b, n):
    xk = np.zeros((n+1,), dtype=np.float128)

    for k in range (0,n+1):
        xk[k] = ((a+b) / 2.0) - ((b-a) / 2.0) * m.cos(float(k)/n * m.pi)

    return xk

#gera pontos para letra C
def gerarPontos_c(a, b, n):
    xk = np.zeros((n+1,), dtype=np.float128)

    for k in range (0,n+1):
        xk[k] = -1.0 + (2.0 * k) / float(n)

    return xk

##### Geradores de graficos #####

def gerarGrafico(tempo, solucao_aproximada, solucao_exata, metodo, ordem):

    #print("len tempo: ", len(tempo))
    #print("len solucao_aproximada: ", len(solucao_aproximada))
    #print("len solucao_exata: ", len(solucao_exata))

     #plota grafico da função
    plt.plot(
        tempo, solucao_exata, 'b--',
        tempo, solucao_aproximada, 'r-'
        )
    #plt.ylabel(u"Valor de f(x), P(x)") #esse 'u' antes da string é pra converter o texto pra unicode
    #plt.xlabel(u"Valor de x, " + str(len(tempo)) + u" partições")
    plt.xlabel(str(len(tempo)) + u" partições, N = " + str(ordem))

    #legendas do grafico
    se_line = mlines.Line2D([], [], color='blue', marker='', markersize=0, label=u'Sol Exata')
    ac_line = mlines.Line2D([], [], color='red', marker='', markersize=0, label=u'Met. ' + metodo)

    plt.legend(handles=[se_line, ac_line])

    plt.title(u"Metodo "+metodo+u" x Solução exata", )

    #plt.axis([0, 50, 0, 100])
    plt.show()

def gerarGraficoErro(tempo, solucao_aproximada, solucao_exata, metodo, ordem):

    #print("len tempo: ", len(tempo))
    #print("len solucao_aproximada: ", len(solucao_aproximada))
    #print("len solucao_exata: ", len(solucao_exata))

    arr_erro = np.zeros((len(tempo),), dtype=np.float128)

    #gera array com a comparacao do erro
    for k in range (0, num_particoes):
        arr_erro[k] = abs(solucao_aproximada[k] - solucao_exata[k])

     #plota grafico da função
    plt.plot(
        tempo, arr_erro, 'b--'
        )
    #plt.ylabel(u"Erro f(x) - P(x)") #esse 'u' antes da string é pra converter o texto pra unicode
    #plt.xlabel(u"Valor de x, " + str(len(tempo)) + u" partições")
    plt.xlabel(str(len(tempo)) + u" partições, N = " + str(ordem))

    #legendas do grafico
    se_line = mlines.Line2D([], [], color='blue', marker='', markersize=0, label=u'Erro')

    plt.legend(handles=[se_line])

    plt.title(u"Erro relativo do metodo "+metodo)

    #plt.axis([0, 50, 0, 100])
    plt.show()

#configura grafico
num_particoes = 100
N = 6
a = -1.0
b = 1.0

#gera os pontos pra interpolacao
pontos = gerarPontos_a(a, b, N)

#inicia os arrays do numpy com 128bits de precisao
particoes = np.zeros((num_particoes,), dtype=np.float128)
sol_exata = np.zeros((num_particoes,), dtype=np.float128)
sol_aprox = np.zeros((num_particoes,), dtype=np.float128)

#gera array com a solucao exata e particoes do grafico
dp = (b-a) / num_particoes
for k in range (0, num_particoes):
    x = a + dp * k
    particoes[k] = x
    sol_exata[k] = F(x)

#gera array com pontos pra interpolacao
num_pontos = len(pontos)
y = np.zeros((num_pontos,), dtype=np.float128)
for k in range (0, num_pontos):
    y[k] = F(pontos[k])

'''
print(particoes)
print(pontos)
print(y)
'''

'''
print("")
print("------")
print("")

#inicio = Utils().getTime()
#Newton().interpolacao(pontos, vy);
coeficientes = Newton().interpolacaoSlide(num_pontos, pontos, y);

#gera array com a solucao aproximada
for k in range (0, num_particoes):
    #sol_aprox[k] = Newton().avaliarPonto(particoes[k])
    sol_aprox[k] = Newton().avaliarPontoSlide(num_pontos, particoes[k], pontos, coeficientes)

#fim  = Utils().getTime()
#Utils().imprimeDiferencaTempo(inicio, fim)
erroNorma = Utils().distanciaMaximo(sol_exata, sol_aprox)
print("Erro (Norma do Maximo): " + repr(erroNorma))

gerarGrafico(particoes, sol_aprox, sol_exata, "Newton", N)
gerarGraficoErro(particoes, sol_aprox, sol_exata, "Newton", N)
'''

print("")
print("------")
print("")

#inicio = Utils().getTime()

#gera array com a solucao aproximada
for k in range (0, num_particoes):
    sol_aprox[k] = Lagrange().interpolacao(num_pontos, pontos, y, particoes[k]);

#fim  = Utils().getTime()
#Utils().imprimeDiferencaTempo(inicio, fim)
erroNorma = Utils().distanciaMaximo(sol_exata, sol_aprox)
print("Erro (Norma do Maximo): " + repr(erroNorma))

gerarGrafico(particoes, sol_aprox, sol_exata, "Lagrange", N)
gerarGraficoErro(particoes, sol_aprox, sol_exata, "Lagrange", N)

print("")
print("------")
print("")

#inicio = Utils().getTime()

#gera array com a solucao aproximada
for k in range (0, num_particoes):
    sol_aprox[k] = Linear().interpolacao(num_pontos, pontos, y, particoes[k]);

#fim  = Utils().getTime()
#Utils().imprimeDiferencaTempo(inicio, fim)
erroNorma = Utils().distanciaMaximo(sol_exata, sol_aprox)
print("Erro (Norma do Maximo): " + repr(erroNorma))

gerarGrafico(particoes, sol_aprox, sol_exata, "Linear", N)
gerarGraficoErro(particoes, sol_aprox, sol_exata, "Linear", N)


# daub.py
## This is my implementation of daub.m
## Computation of Daubechies' filter coefficients (cepstrum method)
## using Python libraries numpy, scipy
##
## The main reference that I'll use is
## Gilbert Strang, and Kevin Amaratunga. 18.327 Wavelets, Filter Banks and Applications, Spring 2003. (Massachusetts Institute of Technology: MIT OpenCourseWare), http://ocw.mit.edu (Accessed 19 Jun, 2015). License: Creative Commons BY-NC-SA
## daub.py dovetails with Handout 8 and I explain it in my notes On 18.327 Wavelets pdf.
##
##
#####################################################################################
## Copyleft 2015, Ernest Yeung <ernestyalumni@gmail.com>
##
## 20150630
##
## This program, along with all its code, is free software;
## you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You can have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software Foundation, Inc.,
## S1 Franklin Street, Fifth Floor, Boston, MA
## 02110-1301, USA
##
## Governing the ethics of using this program, I default to the Caltech Honor Code:
## ``No member of the Caltech community shall take unfair advantage of
## any other member of the Caltech community.''
##
## If you like what I'm doing and would like to help and contribute support,
## please take a look at my crowdfunding campaign at ernestyalumni.tilt.com
## and subscription-based Patreon
## read my mission statement and give your financial support,
## no matter how small or large,
## if you can
## and to keep checking my ernestyalumni.wordpress.com blog and
## various social media channels
## for updates as I try to keep putting out great stuff.
##
## Fund Science! Help my physics education outreach and research efforts at
## Open/Tilt or subscription Patreon - Ernest Yeung
##
## ernestyalumni.tilt.com
##
## Facebook     : ernestyalumni
## gmail        : ernestyalumni
## google       : ernestyalumni
## linkedin     : ernestyalumni
## Patreon      : ernestyalumni
## Tilt/Open    : ernestyalumni
## tumblr       : ernestyalumni
## twitter      : ernestyalumni
## youtube      : ernestyalumni
## wordpress    : ernestyalumni
##
##
################################################################################
##
##
##
##
##

import numpy as np
import scipy

# much credit should go to Kevin Amaratunga for writing the daub.m Matlab file implementing
# Daubeschies orthogonal wavelets first, of which this Python file is based upon.
# I hope that translating daub.m to Python, and the documentation (see my wordpress.com blog and look for the Wavelets pdf write up on 18.327) I'm continually doing will help
# extend the its use

def daub(Nh):

    """
    function h = daub(Nh)

    Generate filter coefficients for the Daubechies orthogonal wavelets.

    Kevin Amaratunga
    9 December, 1994.

    h = filter coefficients of Daubechies orthonormal compactly supported
        wavelets
    Nh = length of filter.

    EY:20150630 I've implemented daub.m in Python with numpy, scipy ernestyalumni.wordpress.com
    """

    K = Nh/2
    L = Nh/2.  # EY : 20150630 you need L to be a float to match the results of daub.m
    N = 512 # Use a 512 point FFT by default
    k = np.array(range(N))

    # Determine samples of the z transform of Mz (= Mz1 Mz2) on the unit circle.
    # Mz2 = z.^L .* ((1 + z.^(-1)) / 2).^(2*L); # or in Python numpy
    # Mz2 = np.multiply( np.power(z, L) , np.power( (( 1+ np.power(z,-1))/2.) , (2*L) ) )

    z = np.exp( 2j*np.pi*k/N)
    tmp1 = (1 + np.power( z,-1 ) )/2
    tmp2 = (-z + 2 - np.power(z,-1) )/4 # sin^2(w/2)

    Mz1 = np.zeros(N)
    vec = np.ones(N)
    for l in range(K):
        # Mz1 = Mz1 + binomial(L+l-1,l) * tmp2.^l;
        Mz1 = Mz1 + vec
        vec = np.multiply( vec, tmp2*(L+l)/(l+1) )  # you need L to be a float to match the results of daub.m

    Mz1 = 4 * Mz1

    # Mz1 has no zeros on the unit circle, so use the complex cepstrum to find
    # its minimum phase spectral factor

    Mz1hat = np.log(Mz1)
    m1hat = np.fft.ifft( Mz1hat )     # Real cepstrum of np.fft.ifft(Mz1). (= cmplx
                                      # cepstrum since Mz1 real, +ve.)
    m1hat[N/2:N] = np.zeros(N/2)  # Retain just the causal part.
    m1hat[0] = m1hat[0]/2             # Value at zero is shared between
                                      # the causal and anticausal part.
    G = np.exp(np.fft.fft(m1hat,N))   # Min phase spectral factor of Mz1

    # Mz2 has zeros on the unit circle, but its minimum phase spectral factor
    # is just tmp1.^L i.e. np.power( tmp1, L )
    Hz = np.multiply( G, np.power( tmp1, L ) )  # you need L to be a float to match the results of daub.m
    h = np.real( np.fft.ifft(Hz) ) # there are problems here with precision

# EY : 20150630 there is a difference of precision between GNU Octave and Python numpy
# cf. http://stackoverflow.com/questions/8717099/ifft-in-matlab-and-numpy-give-different-results
# This might be promising for increasing speed and making grids, including numba
# cf. https://jakevdp.github.io/blog/2015/02/24/optimizing-python-with-numpy-and-numba/

    h = np.vstack( h[0:Nh] )
    return h


from engine.functions.anomaly_computation import compute_eccentric_anomaly
from sympy import acos, atan, cos, pi, sin, sqrt, tan
from sympy.utilities.lambdify import implemented_function

def TrueAnomalyAtT(true_anomaly_at_epoch, eccentricity, period, t):
    eccentric_anomaly_at_epoch = EccentricAnomalyFromTrueAnomaly(
        true_anomaly_at_epoch, eccentricity
    )
    mean_anomaly_at_epoch = MeanAnomalyFromEccentricAnomaly(
        eccentric_anomaly_at_epoch, eccentricity
    )

    mean_anomaly = MeanAnomalyAtT(mean_anomaly_at_epoch, period, t)

    eccentric_anomaly = EccentricAnomalyFromMeanAnomaly(mean_anomaly, eccentricity)
    return TrueAnomalyFromEccentricAnomaly(eccentric_anomaly, eccentricity)

def EccentricAnomalyFromTrueAnomaly(true_anomaly, eccentricity):
    return acos(
        (eccentricity + cos(true_anomaly)) / (1 + eccentricity * cos(true_anomaly))
    )

def MeanAnomalyFromEccentricAnomaly(eccentric_anomaly, eccentricity):
    return eccentric_anomaly - eccentricity * sin(eccentric_anomaly)

def MeanAnomalyAtT(mean_anomaly_at_epoch, period, t):
    return mean_anomaly_at_epoch + (2 * pi / period) * t

EccentricAnomalyFromMeanAnomaly = implemented_function(
    "Ecc",
    lambda mean_anomaly, eccentricity: compute_eccentric_anomaly(
        float(mean_anomaly), float(eccentricity)
    ),
)

def TrueAnomalyFromEccentricAnomaly(eccentric_anomaly, eccentricity):
    return 2 * atan(
        sqrt((1 + eccentricity) / (1 - eccentricity)) * tan(eccentric_anomaly / 2)
    )


from math import atan
import numpy as np

class YawController(object):
    def __init__(self, wheel_base, steer_ratio, min_speed, max_lat_accel, max_steer_angle, kp):
        self.wheel_base = wheel_base
        self.steer_ratio = steer_ratio
        self.min_speed = min_speed
        self.max_lat_accel = max_lat_accel

        self.min_angle = -max_steer_angle
        self.max_angle = max_steer_angle

        self.kp = kp

    def get_angle(self, radius):
        angle = atan(self.wheel_base / radius) * self.steer_ratio
        return max(self.min_angle, min(self.max_angle, angle))

    def get_steering(self, linear_velocity, angular_velocity, current_velocity):
        angular_velocity = current_velocity * angular_velocity / linear_velocity if abs(linear_velocity) > 0. else 0.

        if abs(current_velocity) > 0.1:
            max_yaw_rate = abs(self.max_lat_accel / current_velocity);
            angular_velocity = max(-max_yaw_rate, min(max_yaw_rate, angular_velocity))

        return self.get_angle(max(current_velocity, self.min_speed) / angular_velocity) if abs(angular_velocity) > 0. else 0.0;

    def get_steering_P(self, pose, p1, p2):
        # this use closest pt and second closest pt to form a line and calculate
        # offset of the current position and time kp
        # https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
        d = np.cross(p2-p1, p1-pose) / np.linalg.norm(p2-p1)
        angle = self.kp * d
        return  max(self.min_angle, min(self.max_angle, angle))


import matplotlib.pyplot as plt
import numpy as np
from scipy.fftpack import fft, fftshift

plt.figure(1, figsize=(9.5, 7))
M = 64
N = 64
x1 = np.hanning(M)
x2 = np.cos(2*np.pi*2/M*np.arange(M))
y1 = x1*x2
mY1 = 20 * np.log10(np.abs(fftshift(fft(y1, N))))

plt.subplot(3,2,1)
plt.title('x1 (hanning)')
plt.plot(np.arange(-M/2, M/2), x1, 'b', lw=1.5)
plt.axis([-M/2,M/2,0,1])

plt.subplot(3,2,2)
plt.title('x2 (cosine)')
plt.plot(np.arange(-M/2, M/2),x2, 'b', lw=1.5)
plt.axis([-M/2,M/2,-1,1])

mX1 = 20 * np.log10(np.abs(fftshift(fft(x1, M)))/M)
plt.subplot(3,2,3)
plt.title('X1')
plt.plot(np.arange(-N/2, N/2),mX1, 'r', lw=1.5)
plt.axis([-N/2,N/2,-80,max(mX1)])

mX2 = 20 * np.log10(np.abs(fftshift(fft(x2, M)))/M)
plt.subplot(3,2,4)
plt.title('X2')
plt.plot(np.arange(-N/2, N/2),mX2, 'r', lw=1.5)
plt.axis([-N/2,N/2,-80,max(mX2)])

plt.subplot(3,2,5)
plt.title('DFT(x1 x x2)')
plt.plot(np.arange(-N/2, N/2),mY1, 'r', lw=1.5)
plt.axis([-N/2,N/2,-80,max(mY1)])

Y2 = np.convolve(fftshift(fft(x1, M)), fftshift(fft(x2, M)))
mY2 = 20 * np.log10(np.abs(Y2)) - 40

plt.subplot(3,2,6)
plt.title('X1 * X2')
plt.plot(np.arange(-N//2, N//2),mY2[M//2:M+M//2], 'r', lw=1.5)
plt.axis([-N/2,N/2,-80,max(mY2)])

plt.tight_layout()
plt.savefig('convolution-2.png')
plt.show()


import numpy as np

# define sigmoid
def sigmoid(x):
    return 1/(1+np.exp(-x))

# define derivative of sigmoid
def sigmoid_prime(x):
    return sigmoid(x) * (1-sigmoid(x))

# weight initialization
weight = np.array([-0.8, 0.5])
# input
x = np.array([0.1, 0.3])
# output
y = 0.2
# learning rate
learning_rate = 0.5

# linear combination
h = np.dot(x, weight)

# neural network output (y_hat)
y_hat = sigmoid(h)

# error (y - y_hat)
error = y - y_hat

# error term
error_term = error * sigmoid_prime(h)

# gradient descent step
del_w = learning_rate * error_term * x

print(del_w)

### Expect output
[-0.0039638  -0.01189141]
###


import numpy as np
from sklearn.cluster import KMeans
from sklearn.metrics import normalized_mutual_info_score as NMI
from sklearn.decomposition import PCA

# Load dataset embeddings and labels.
obj = np.load('mit67_embeddings.npz')
labels = obj['labels']
embeddings = obj['embeddings']

# Set up the subset of labels to visualize.
n_labels = 5
_uniq = np.unique(labels)[:n_labels]
print('The {n} labels selected to clusterize:'.format(n=n_labels), _uniq)

# Create the embeddings matrix (and its corresponding labels list)
# containing instances belonging to labels in the previous subset.
subsets_emb = np.zeros((0,4096))
true_labels = []
for idx, _lab in enumerate(_uniq):
    part_emb = embeddings[np.where(labels == _lab)]
    subsets_emb = np.concatenate((subsets_emb, part_emb))
    true_labels += [_lab for _ in range(part_emb.shape[0])]
true_labels = np.array(true_labels)

# Use a dimensionality reduction technique (e.g., PCA).
reduced_emb = PCA(n_components=100).fit_transform(subsets_emb)

# Apply a clustering technique (e.g., KMeans) and evaluate its performance with
# a metric (e.g., Normalized Mutual Information).
pred_labels = KMeans(n_clusters=n_labels, random_state=0).fit_predict(reduced_emb)
nmi = NMI(true_labels, pred_labels)
print('NMI score:', nmi)


import numpy as np

def MakeFromPolar(r: float, theta: float, phi: float) -> np.ndarray:
    """
    Convert from polar coordinates to cartesian coordinates
    """
    # get sine and cosine of the angles
    ct = np.cos(theta)
    st = np.sin(theta)
    cp = np.cos(phi)
    sp = np.sin(phi)
    # and convert to cartesian coordinates
    x = r * st * cp
    y = r * st * sp
    z = r * ct
    # create the array
    return np.array([x, y, z])

def buildBeams(N: int) -> np.ndarray:
    """
    Builds a sphere of unit vectors with N beams in the xy plane.
    """
    N = int(np.floor(np.sqrt(int(N) * np.pi + 0.5)))

    # start with an empty list
    beams = []

    # iterate over the whole angle in the xy plane
    for i in range(N):
        # get the Nth part of the total rotation
        theta = (2 * np.pi / N) * i

        # estimate how many vectors we need to cover the phi angle (for the z direction)
        jmax = int(np.floor(N * np.sin(theta) + 0.5))

        # iterate over those angles to get beams in every direction
        for j in range(jmax):
            # get the phi angle
            phi = (2 * np.pi / jmax) * j

            # and create a unit vector from the polar coordinates theta and phi
            beams.append(MakeFromPolar(1.0, theta, phi))

    # return all the vectors
    return np.array(beams)

def saveBeams(beams: np.ndarray, fname: str):
    np.savetxt(fname, beams)


# -*- coding: utf-8 -*-
import numpy as np

v1 = np.mat([1, 2, 3])
v2 = np.mat([5, 7, 9])

print('v1 = {0}, v2 = {1}'.format(v1, v2))

def manhattan(x1, x2):
    return np.sum(np.abs(x1 - x2))

def euclidean(x1, x2):
    v = x1 - x2
    return np.sqrt(np.dot(v, v.T))

def chebyshev(x1, x2):
    return np.max(np.abs(x1 - x2))

print('manhattan = {0}\neuclidean = {1}\nchebyshev = {2}'.format(manhattan(v1, v2), euclidean(v1, v2).item(0), chebyshev(v1, v2)))


import numpy as np
import math

def get_num_windows(image_height, image_width, window_height, window_width, overlap=True, overlap_corners=True):
    """Return the number of height and width windows to generate

    Args:
        image_height: Height of the image in pixels.
        image_width: Width of the image in pixels.
        window_height: The height of each generated window.
        window_width: The width of each generated window.
        overlap: True iff generated windows should be overlapped.
        overlap_corners: True iff the corners/edges should be mirrored and contain
          as many overlaps as the centre of the image.

    Returns:
        A 3-element list containing the total number of windows, and the number of
        windows needed for the image height and width, respectively.
    """
    if not overlap:
        num_height_windows = math.ceil(image_height/window_height)
        num_width_windows = math.ceil(image_width/window_width)
    elif overlap_corners:
        num_height_windows = math.ceil(image_height/(window_height/2)) + 1
        num_width_windows = math.ceil(image_width/(window_width/2)) + 1
    else:
        num_height_windows = max(1, math.ceil(image_height/(window_height/2)) - 1)
        num_width_windows = max(1, math.ceil(image_width/(window_width/2)) - 1)

    return ((num_height_windows*num_width_windows), num_height_windows, num_width_windows)

def split_image_to_windows(image, window_height, window_width, overlap=True, overlap_corners=True):
    """Split an input image into multiple equal-sized windows.

    The input image can have any dimensions. It will be split into multiple
    equal-sized windows.

    Args:
        image: Input image with 3 dimensions - height, width, and channels.
        window_height: The height of each generated window.
        window_width: The width of each generated window.
        overlap: True iff generated windows should be overlapped.
        overlap_corners: True iff the corners/edges should be mirrored and contain
          as many overlaps as the centre of the image.

    Returns:
        Numpy 4-d array, dimensions are the window index, window height, window
        width, channel data. The returned shape[0] describes how many total
        windows were created.
    """
    img_height = image.shape[0]
    img_width = image.shape[1]

    (total_windows, num_height_windows, num_width_windows) = get_num_windows(img_height, img_width,
                                                                             window_height, window_width,
                                                                             overlap, overlap_corners)

    window_images = np.zeros((total_windows, window_height, window_width, image.shape[2]), image.dtype)

    src_window_height = int(window_height/2)
    src_window_width = int(window_width/2)

    # Training with overlapping windows, including overlaps for corners/edges, provides the
    # best IoU/LB scores. If training was not done using overlaps for corners/edges, then
    # predictions using overlaps without additional corner/edge windows provided the best
    # IoU/LB score.
    if not overlap_corners:
        src_window_height = window_height
        src_window_width = window_width
        if overlap > 0:
            src_window_height = int(src_window_height/2)
            src_window_width = int(src_window_width/2)

        cur_window = 0
        for h in range(num_height_windows):
            for w in range(num_width_windows):
                # The right-most and bottom-most windows of the image may need to
                # be padded. If we are at the edge of the input image, we will pad
                # the output windows. Determine how much is left to copy from the
                # input image, and the padding will then be the difference between
                # the end of the window, and the edge of the input image.
                image_edge_height = min(img_height, window_height + (h * src_window_height))
                image_edge_width = min(img_width, window_width + (w * src_window_width))

                window_pad_height = (window_height + (h * src_window_height)) - image_edge_height
                window_pad_width = (window_width + (w * src_window_width)) - image_edge_width

                window_images[cur_window] = np.pad(image[h * src_window_height:image_edge_height,
                                                         w * src_window_width:image_edge_width,:],
                                                   ((0,window_pad_height),(0,window_pad_width),(0,0)),
                                                   'symmetric')
                cur_window += 1
    else:
        cur_window = 0
        for h in range(num_height_windows):
            # The corners and edges need to be padded using symmetric padding.
            src_top = max(0, (h - 1) * src_window_height)
            src_bottom = min(img_height, (h + 1) * src_window_height)

            pad_top = 0
            if h == 0:
                pad_top = src_window_height
            pad_bottom = window_height - pad_top - (src_bottom - src_top)

            for w in range(num_width_windows):
                src_left = max(0, (w - 1) * src_window_width)
                src_right = min(img_width, (w + 1) * src_window_width)

                pad_left = 0
                if w == 0:
                    pad_left = src_window_width
                pad_right = window_width - pad_left - (src_right - src_left)

                window_images[cur_window] = np.pad(image[src_top:src_bottom,src_left:src_right,:],
                                                   ((pad_top,pad_bottom),(pad_left,pad_right),(0,0)),
                                                   'symmetric')
                cur_window += 1

    return window_images

def stitch_single_image(windows, image_height, image_width, overlap=True, overlap_corners=True):
    """Stitch together an image that had been split into multiple equal-sided windows.

    Args:
        windows: All the windows of the image to be stitched together.
        image_height: The original height of the image to be stitched back together.
        image_width: The original width of the image to be stitched back together.
        overlap: True iff generated windows should be overlapped.
        overlap_corners: True iff the corners/edges should be mirrored and contain
          as many overlaps as the centre of the image.

    Returns:
        Numpy 3-d array/image of the specified image_height and image_width.
    """
    window_height = windows[0].shape[0]
    window_width = windows[0].shape[1]
    (_, num_height_windows, num_width_windows) = get_num_windows(image_height, image_width,
                                                                 window_height, window_width,
                                                                 overlap, overlap_corners)

    dest_img = np.zeros((image_height, image_width, windows[0].shape[2]), dtype=windows[0].dtype)
    cur_window = 0

    # Training with overlapping windows, including overlaps for corners/edges, provides the
    # best IoU/LB scores. If training was not done using overlaps for corners/edges, then
    # predictions using overlaps without additional corner/edge windows provided the best
    # IoU/LB score.
    dest_window_height = window_height
    dest_window_width = window_width
    if not overlap:
        # No overlapping windows
        for h in range(num_height_windows):
            # dest is full-size img, src is current window
            end_start_height = h * window_height
            end_dest_height = min(image_height, end_start_height + window_height)
            end_src_height = end_dest_height - end_start_height

            for w in range(num_width_windows):
                end_start_width = w * window_width
                end_dest_width = min(image_width, end_start_width + window_width)
                end_src_width = end_dest_width - end_start_width
                src_image = windows[cur_window]
                cur_window += 1
                dest_img[end_start_height:end_dest_height,end_start_width:end_dest_width] = src_image[0:end_src_height,0:end_src_width]
    elif overlap_corners:
        dest_window_height = int(dest_window_height/2)
        dest_window_width = int(dest_window_width/2)

        for h in range(num_height_windows):
            # dest is full-size img, src is current window
            dest_top = max(0, (h - 1) * dest_window_height)
            dest_bottom = min(image_height, (h + 1) * dest_window_height)

            if h == 0:
                src_top = dest_window_height
            else:
                src_top = 0
            src_bottom = src_top + (dest_bottom - dest_top)

            for w in range(num_width_windows):
                dest_left = max(0, (w - 1) * dest_window_width)
                dest_right = min(image_width, (w + 1) * dest_window_width)
                if w == 0:
                    src_left = dest_window_width
                else:
                    src_left = 0
                src_right = src_left + (dest_right - dest_left)

                # Scale down the input window, the edges won't have 4 overlapping windows,
                # (they will have either 1 or 2 overlapping windows), but we discard all
                # edges anyways.
                src_image = windows[cur_window].copy()
                src_image[:,:] = src_image[:,:] / 4

                cur_window += 1
                dest_img[dest_top:dest_bottom,dest_left:dest_right] += src_image[src_top:src_bottom,src_left:src_right]
    else:
        if image_height > dest_window_height:
            dest_window_height = int(dest_window_height/2)
        if image_width > dest_window_width:
            dest_window_width = int(dest_window_width/2)

        for h in range(num_height_windows):
             # dest is full-size img, src is current window
            dest_start_height = h * dest_window_height
            dest_end_height = min(image_height, dest_start_height + window_height)
            src_end_height = dest_end_height - dest_start_height

            for w in range(num_width_windows):
                dest_start_width = w * dest_window_width
                dest_end_width = min(image_width, dest_start_width + window_width)
                src_end_width = dest_end_width - dest_start_width

                src_image = windows[cur_window].copy()
                # Scale down the input window based on how many windows overlap each
                # quarter of the window.
                q1 = 1
                q2 = 1
                q3 = 1
                q4 = 1
                if (h == 0 and w > 0) or (w == 0 and h > 0):
                    q1 = 2
                elif (h > 0 and w > 0):
                    q1 = 4
                if (h == 0 and w < (num_width_windows - 1)) or (h > 0 and w == (num_width_windows - 1)):
                    q2 = 2
                elif (h > 0 and w < (num_width_windows - 1)):
                    q2 = 4
                if (h < (num_height_windows - 1) and w == 0) or (h == (num_height_windows - 1) and w > 0):
                    q3 = 2
                elif (h < (num_height_windows - 1)) and w > 0:
                    q3 = 4
                if (h < (num_height_windows - 1) and w == (num_width_windows - 1)) or (h == (num_height_windows - 1) and w < (num_width_windows - 1)):
                    q4 = 2
                elif (h < (num_height_windows - 1)) and (w < (num_width_windows - 1)):
                    q4 = 4
                src_image[0:dest_window_height,0:dest_window_width] = src_image[0:dest_window_height,0:dest_window_width] / q1
                src_image[0:dest_window_height,dest_window_width:window_width] = src_image[0:dest_window_height,dest_window_width:window_width] / q2
                src_image[dest_window_height:window_height,0:dest_window_width] = src_image[dest_window_height:window_height,0:dest_window_width] / q3
                src_image[dest_window_height:window_height,dest_window_width:window_width] = src_image[dest_window_height:window_height,dest_window_width:window_width] / q4

                cur_window += 1
                dest_img[dest_start_height:dest_end_height,dest_start_width:dest_end_width] += src_image[0:src_end_height,0:src_end_width]

    return dest_img

def stitch_all_images(windows, sizes, overlap=True, overlap_corners=True):
    """Stitch together the provided windows into a list of original-sized images.

    Args:
        windows: All the windows of all the images to be stitched together.
        sizes: The original image sizes.
        overlap: True iff generated windows should be overlapped.
        overlap_corners: True iff the corners/edges should be mirrored and contain
          as many overlaps as the centre of the image.

    Returns:
        List of numpy 3-d array/images stitched together from the input windows.
    """
    stitched = []
    cur_window = 0
    window_height = windows[0].shape[0]
    window_width = windows[0].shape[1]

    for (image_height, image_width) in sizes:
        (image_windows, _, _) = get_num_windows(image_height, image_width, window_height, window_width, overlap, overlap_corners)
        end_window = cur_window + image_windows
        stitched.append(stitch_single_image(windows[cur_window:end_window], image_height, image_width, overlap, overlap_corners))
        cur_window = end_window

    return stitched


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

t = np.arange(0, 5, 0.1)
y1 = np.sin(np.pi * t)
y2 = np.sin(np.pi * t + np.pi / 2)
y3 = np.sin(np.pi * t - np.pi / 2)

plt.plot(t, y1, t, y2, t, y3)
plt.show()


import numpy as np
def std_deviation(arr_x,arr_y):
    # arr_y = np.zeros((len(data)))
    # arr_x = np.zeros((len(data)))
    # for i in range(len(data)):
    #    arr_x[i] = data[i][0]
    #    arr_y[i] = data[i][1]
    mean_x = np.mean(arr_x)
    mean_y = np.mean(arr_y)
    std_x = np.std(arr_x)
    std_y = np.std(arr_y)
    print (len(arr_x), len(arr_y))
    data_filter_x = []
    data_filter_y = []

    for i in range(len(arr_x)):
        if arr_x[i] > mean_x - 1.5 * std_x and \
           arr_x[i] < mean_x + 1.5 * std_x:
            data_filter_x.append(arr_x[i])
    for i in range(len(arr_y)):
        if arr_y[i] > mean_y - 1.5 * std_y and \
           arr_y[i] < mean_y + 1.5 * std_y:
            data_filter_y.append(arr_y[i])
                # data_filter.append([arr_x[i], arr_y[i]])
    # print (data_filter_x, data_filter_y)
    print (std_x, std_y)
    print (mean_x, mean_y)
    print (len(data_filter_x), len(data_filter_y))
    # print (data_filter)
    right_eye = (np.array(data_filter_x))
    left_eye = (np.array(data_filter_y))
    print(np.std(left_eye), np.std(right_eye))
    left_mean = np.mean(left_eye)
    right_mean = np.mean(right_eye)
    print(left_mean, right_mean)
    return left_mean - right_mean


import pandas
import numpy as np

class CalmarRatioIndicator(object):
    """ Calmar Ratio of a trading strategy KPI """
    KPIdf: np.float64

    def __init__(self, a_df: pandas.DataFrame):
        self.__setIndicator(a_df)

    def __setIndicator(self, a_df: pandas.DataFrame):
        """function to calculate Calmar Ratio"""
        df: pandas.DataFrame = a_df.copy()
        self.KPIdf = self.__getCagr(df) / self.__getMaxDrawDown(df)

    @staticmethod
    def __getCagr(a_df: pandas.DataFrame):
        """function to calculate the Cumulative Annual Growth Rate of a trading strategy"""
        df: pandas.DataFrame = a_df.copy()
        df['DailyReturn'] = a_df['Adj Close'].pct_change()
        df['CumulativeReturn'] = (1 + df['DailyReturn']).cumprod()
        annual_length = len(df) / 252
        return (df['CumulativeReturn'][-1]) ** (1 / annual_length) - 1

    @staticmethod
    def __getMaxDrawDown(a_df: pandas.DataFrame):
        """function to calculate the Maximum Draw Down of a trading strategy"""
        df: pandas.DataFrame = a_df.copy()
        df['DailyReturn'] = a_df['Adj Close'].pct_change()
        df['CumulativeReturn'] = (1 + df['DailyReturn']).cumprod()
        df['CumulativeRollMax'] = df['CumulativeReturn'].cummax()
        df['DrawDown'] = df['CumulativeRollMax'] - df['CumulativeReturn']
        df['DrawDownPercent'] = df['DrawDown'] / df['CumulativeRollMax']
        return df['DrawDownPercent'].max()


from numpy.linalg import cond
from scipy import zeros
from scipy.interpolate import CubicSpline
from scipy.linalg import solve
from gauss import gauss
from roots_legendre_interval import roots_legendre_interval

def integral_equation(K, f, a, b, n = 5, use_python_libs = False):
    x, w = roots_legendre_interval(n, a, b, use_python_libs=use_python_libs)
    matrix = zeros((n, n + 1))
    for i in range(n):
        for j in range(n):
            matrix[i, j] = w[j] * K(x[i], x[j])
        matrix[i, n] = f(x[i])
    y = solve(matrix[:, 0: -1], matrix[:, -1]) if use_python_libs else gauss(matrix)
    assert len(x) == len(y), f'len(x) = {len(x)}, len(y) = {len(y)}'
    result = CubicSpline(x, y)
    return result, cond(matrix)


import numpy as np
import numpy.matlib
from scipy.integrate import quad
from scipy.integrate import simps

def lagrange_k(x, nodes, k):
    nodes_but = np.delete(nodes,k)
    D = x-nodes_but[:,None]
    N = nodes[k]-nodes_but
    l_k = np.prod(D/N[:,None], axis = 0 )
    return l_k

def quadrature_weights(nodes, interval, mapping = None):
    N_nodes = len(nodes)
    a,b = interval
    if mapping is None:
        mapping = lambda x: x
    lagr = lambda y,k: lagrange_k(mapping(y),mapping(nodes),k)
    weights = [ quad( lagr, a, b, epsabs = 1.e-9, limit=250, args=(k,))[0] for k in range(N_nodes) ]
    #x = np.linspace( a, b, 10*N_nodes+1 )
    #weights = [ simps(lagr(x,k), x) for k in range(N_nodes) ]
    return np.array(weights)


import numpy as np

# In-buold numpy array manipulation methods

######## Changing Shapes #########

'''

# reshape: Gives a new shape to an array without changing its data
# Syantax: numpy.reshape(arr, newshape, order')
# arr -> source array
# newshape -> tuple of the shape. Note it has to be compatilble with original shape
# order -> C-style (row-wise), F-stype (column-wise)

a = np.arange(24)
b = a.reshape(3,8)
c = a.reshape(8,3)
d = a.reshape(2,3,4)
print("Reshaped array: ", a)
print("Reshaped array: ", b)
print("Reshaped array: ", c)
print("Reshaped array: ", d)
'''

'''
# flaten: returns a copy of an array collapsed into one dimension
# Syantax: ndarray.flatten(order)
# order: C-style (row-wise), F-stype (column-wise)

a = np.arange(10).reshape(2,5)
print("Original array: ", a)
b = a.flatten()
print("Flattened 1-array: ", b)
'''

###### Transpose ops #####
'''
# traspose: permutes the dimension of the given array. It returns a view wherever possible.
# Syantax: numpy.transpose(arr, axes)
# arr -> numpy array to be transposed
# axes -> List of ints, corresponding to the dimensions. By default, the dimensions are reversed

a = np.arange(24).reshape(2, 3, 4)
print("Original array: \n", a, " \nshape: ", a.shape)
b = np.transpose(a)
print("Transposed array: \n ", b, " \nshape: ", b.shape)
'''

# Another shoter way to perform transpose is arr.T

'''
# swapaxes: interchanges the two axes of an array
# Syantax: numpy.swapaxes(arr, axis1, axis2)

a = np.arange(8).reshape(2,2,2)
print("Original array: \n", a)
print("Swap numbers between axis 2 and axis 0 \n", np.swapaxes(a, 0, 2))

# TODO: a more complex swaping can be done using rollaxis funtion
'''

##### Changing Dimensions or Boradcasting ######

# broadcast: Produces an object that mimics broadcasting
# Syantax: a.broadcast(arr,1 arr2)

'''
x = np.array([[1], [2], [3]])
y = np.array([4, 5, 6])

# tobroadcast x against y
b = np.broadcast(x,y)
print("braodcast array:  \n ")
for (u,v) in b:
    print(u, ",", v)
'''
'''
# braodcast_to: broadcasts an array to a new shape. It returns a read-only view on the original array
# Syantax: numpy.broadcast_to(array, shape, subok)

a = np.arange(4).reshape(1,4)
print('The original array: \n', a)
print("Broadcased array: \n", np.broadcast_to(a, (4,4)))
'''

'''
# expand_dims: This function expands the array by inserting a new axis at the specified position
# Syantax: numpy.expand_dims(arr, axis)
# axis -> Position where new axis to be inserted

x = np.array( [ [1,2], [3,4], [5,6] ] )
print("Original array: \n", x, " shape: ", x.shape)
y = np.expand_dims(x, axis = 0)
print("expanded array: \n", y, " Shape: ", y.shape)
y = np.expand_dims(x, axis = 1)
print("expanded array: \n", y, " Shape: ", y.shape)
'''

'''
# squeeze: This function removes one-dimensional entry from the shape of the given array
# Syantax: numpy.squeeze(arr, axis)
# axis -> int or tuple of int. selects a subset of single dimensional entries in the shape

x = np.arange(9).reshape(1,3,3)

print ('Array X: \n',x)
y = np.squeeze(x)

print ('Array Y: \n', y)

print ('The shapes of X and Y array:' )
print (x.shape, y.shape)
'''

###### Joining arrays ######
'''
# concatenate: This function is used to join two or more arrays of the same shape along a specified axis.
# Syantax: numpy.concatenate((a1, a2, ...), axis)
# axiz-> Axis along which arrays have to be joined. Default is 0

a = np.array( [ [1,2],[3,4] ] )
b = np.array( [ [6,7],[8,9] ] )
c = np.concatenate((a,b), axis = 1)
print("Concatenated array: \n", c, " shape: ", c.shape)
c = np.concatenate((a,b))
print("Concatenated array: \n", c, " shape: ", c.shape)
'''

'''
# stack: This function joins the sequence of arrays along a new axis
# Syantax: numpy.stack(arrays, axis)
# arrays -> Sequence of arrays of the same shape
# axis -> Axis in the resultant array along which the input arrays are stacked

a = np.array( [ [[1,2],[3,4], [5,6] ]] )
b = np.array( [ [[6,7],[8,9], [10,11] ]] )
b1 = np.array( [ [[6,7],[8,9], [10,11] ]] )
print("Shape of a & b: ", a.shape, " ", b.shape)
c = np.stack((a,b, b1), 0)
print("Stacked array along with axis 0: \n", c, " shape: ", c.shape)
c = np.stack((a,b, b1), 1)
print("Stacked array along with axis 1: \n", c, " shape: ", c.shape)

# Note: so the difference between the concatenate and stack is in stacking the given axis is always summed up
# Note: similar to stack there is hstack and vstack functions as well
'''

##### Splitting Array ######

# split: divides the array into subarrays along a specified axis
# Syantax: numpy.split(ary, indices_or_sections, axis)
# indices_or_sections ->
# Can be an integer, indicating the number of equal sized subarrays to be created from the input array.
# If this parameter is a 1-D array, the entries indicate the points at which a new subarray is to be created.

'''
# 1-D Array split
a = np.arange(9)
print("split arrray equally: \n", np.split(a, 3))
print("Split array at given location: \n", np.split(a, [4,7]))

# 2-D array split
a = np.arange(9).reshape(3,3)
print("split arrray equally: \n", np.split(a, 3))
print("Split array at given location: \n", np.split(a, [1,3]))
'''

'''
# hsplit: The numpy.hsplit is a special case of split() function where axis is 1 indicating a horizontal split regardless of the dimension of the input array.
# vsplit: numpy.vsplit is a special case of split() function where axis is 1 indicating a vertical split regardless of the dimension of the input array
a = np.arange(16).reshape(4,4)
print("Original array: \n", a)

b = np.hsplit(a,2)
print ('Horizontal splitting: \n', b)

b = np.vsplit(a, 2)
print ('Vertical splitting: \n', b)
'''

###### Element & Description ######

'''
# resize: This function returns a new array with the specified size.
# If the new size is greater than the original, the repeated copies of entries in the original are contained.
# Syantax: numpy.resize(arr, shape)

a = np.array([[1,2,3],[4,5,6]])
print("Origianl array: \n", a, "Shape: ", a.shape)
b = np.resize(a, (3,2))
print("Resize with same size: \n", b, "Shape: ", b.shape)

b = np.resize(a, (4,4, 2))
print("Resize with greter size: \n", b, "Shape: ", b.shape)
'''
'''
# append: This function adds values at the end of an input array. The append operation is not inplace, a new array is allocated.
# Also the dimensions of the input arrays must match otherwise ValueError will be generated.
# Syantax: numpy.append(arr, values, axis)
# values -> To be appended to arr. It must be of the same shape as of arr (excluding axis of appending)
# axis -> The axis along which append operation is to be done. If not given, both parameters are flattened

a = np.array([[1,2,3],[4,5,6]])
print("Orignial array: \n", a)
print ("append: \n", np.append(a, [7,8,9]))
print ("append axis 0: \n", np.append(a, [[7,8,9]],axis = 0))
print ("append axis 1: \n", np.append(a, [[0,0,0],[7,8,9]],axis = 1))
'''

'''
# inserr: This function inserts values in the input array along the given axis and before the given index. If the type of values is converted to be inserted, it is different from the input array. Insertion is not done in place and the function returns a new array. Also, if the axis is not mentioned, the input array is flattened.
# Syantax: numpy.insert(arr, index, values, axis)
# index -> index before which the insersetion has to be made
# valuse -> values to be inserted
# axis -> The axis along which to insert. If not given, the input array is flattened

x = np.array( [ [1,2,3], [4,5,6] ] )
y = np.insert(x, 4, [10,11])
print("Inserted array with no axis: \n", y)
z = np.insert(x, 1, [10,11, 0], axis = 0)
print("Inserted array with axis = 0: \n", z)
z1 = np.insert(x, 1, [10,11], axis = 1)
print("Inserted array with axis = 1: \n", z1)
'''

# delete: This function returns a new array with the specified subarray deleted from the input array. As in case of insert() function, if the axis parameter is not used, the input array is flattened.
# Syantax: Numpy.delete(arr, index, axis)
# index -> Can be a slice, an integer or array of integers, indicating the subarray to be deleted from the input array
# axis -> The axis along which to delete the given subarray. If not given, arr is flattened

a = np.arange(12).reshape(3,4)
print ('Array flattened before delete operation as axis not used:')
print ("Delete array with no axis: \n", np.delete(a,5))
print ("delte the element with azis=1: \n", np.delete(a,1,axis = 1))
a = np.array([1,2,3,4,5,6,7,8,9,10])
print ("Delete with  slice: \n, ", np.delete(a, np.s_[::2]))


 ## Solve test problem HS15 from the Hock & Schittkowski collection.
 #
 #  min   100 (x2 - x1^2)^2 + (1 - x1)^2
 #  s.t.  x1 x2 >= 1
 #        x1 + x2^2 >= 0
 #        x1 <= 0.5
 #
 #  The standard start point (-2, 1) usually converges to the standard
 #  minimum at (0.5, 2.0), with final objective = 306.5.
 #  Sometimes the solver converges to another local minimum
 #  at (-0.79212, -1.26243), with final objective = 360.4.
 ##
from __future__ import print_function

import numpy
import argparse
from pyoptsparse import Optimization, OPT
parser = argparse.ArgumentParser()
parser.add_argument("--opt", help="optimizer", type=str, default='SLSQP')
parser.add_argument("--storeHistory", help="option to store history",type=int, default=0)
args = parser.parse_args()
optOptions = {}

def objfunc(xdict):
    x = xdict['xvars']
    funcs = {}
    funcs['obj'] = [100*(x[1] - x[0]**2)**2 + (1-x[0])**2]
    conval = numpy.zeros(2, 'D')
    conval[0] = x[0]*x[1]
    conval[1] = x[0] + x[1]**2
    funcs['con'] = conval
    fail = False

    return funcs, fail

def sens(xdict, funcs):
    x = xdict['xvars']
    funcsSens = {}
    funcsSens['obj', 'xvars'] = [2*100*(x[1]-x[0]**2)*(-2*x[0]) - 2*(1-x[0]),
                                  2*100*(x[1]-x[0]**2)]
    funcsSens['con', 'xvars'] = [[x[1], x[0]], [1, 2*x[1]]]

    fail = False

    return funcsSens, fail

# Optimization Object
optProb = Optimization('HS15 Constraint Problem', objfunc)

# Design Variables
lower = [-5, -5]
upper = [0.5,  5]
value = [-2, 1]
optProb.addVarGroup('xvars', 2, lower=lower, upper=upper, value=value)

# Constraints
lower = [1, 0]
upper = [None, None]
optProb.addConGroup('con', 2, lower=lower, upper=upper)

# Objective
optProb.addObj('obj')

# Check optimization problem:
print(optProb)

# Optimizer
opt = OPT(args.opt, options=optOptions)

# Solution
if args.storeHistory:
    histFileName = '%s_hs015_Hist.hst'%(args.opt.lower())
else:
    histFileName = None
# end
sol = opt(optProb, sens=sens,storeHistory=histFileName)

# Check Solution
print(sol)