import pytest
from pytest import approx

from ipyplotly.basevalidators import NumberValidator
import numpy as np

# Fixtures
# --------
@pytest.fixture
def validator(request):
    return NumberValidator('prop', 'parent')

@pytest.fixture
def validator_min_max(request):
    return NumberValidator('prop', 'parent', min=-1.0, max=2.0)

@pytest.fixture
def validator_min(request):
    return NumberValidator('prop', 'parent', min=-1.0)

@pytest.fixture
def validator_max(request):
    return NumberValidator('prop', 'parent', max=2.0)

@pytest.fixture
def validator_aok():
    return NumberValidator('prop', 'parent', min=-1, max=1.5, array_ok=True)

# Array not ok
# ------------
# ### Acceptance ###
@pytest.mark.parametrize('val',
                         [1.0, 0.0, 1, -1234.5678, 54321, np.pi, np.nan, np.inf, -np.inf])
def test_acceptance(val, validator: NumberValidator):
    assert validator.validate_coerce(val) == approx(val, nan_ok=True)

# ### Rejection by value ###
@pytest.mark.parametrize('val',
                         ['hello', (), [], [1, 2, 3], set(), '34'])
def test_rejection_by_value(val, validator: NumberValidator):
    with pytest.raises(ValueError) as validation_failure:
        validator.validate_coerce(val)

    assert 'Invalid value' in str(validation_failure.value)

# ### With min/max ###
@pytest.mark.parametrize('val',
                         [0, 0.0, -0.5, 1, 1.0, 2, 2.0, np.pi/2.0])
def test_acceptance_min_max(val, validator_min_max: NumberValidator):
    assert validator_min_max.validate_coerce(val) == approx(val)

@pytest.mark.parametrize('val',
                         [-1.01, -10, 2.1, 234, -np.inf, np.nan, np.inf])
def test_rejection_min_max(val, validator_min_max: NumberValidator):
    with pytest.raises(ValueError) as validation_failure:
        validator_min_max.validate_coerce(val)

    assert 'in the interval [-1.0, 2.0]' in str(validation_failure.value)

# ### With min only ###
@pytest.mark.parametrize('val',
                         [0, 0.0, -0.5, 99999, np.inf])
def test_acceptance_min(val, validator_min: NumberValidator):
    assert validator_min.validate_coerce(val) == approx(val)

@pytest.mark.parametrize('val',
                         [-1.01, -np.inf, np.nan])
def test_rejection_min(val, validator_min: NumberValidator):
    with pytest.raises(ValueError) as validation_failure:
        validator_min.validate_coerce(val)

    assert 'in the interval [-1.0, inf]' in str(validation_failure.value)

# ### With max only ###
@pytest.mark.parametrize('val',
                         [0, 0.0, -np.inf, -123456, np.pi/2])
def test_acceptance_max(val, validator_max: NumberValidator):
    assert validator_max.validate_coerce(val) == approx(val)

@pytest.mark.parametrize('val',
                         [2.01, np.inf, np.nan])
def test_rejection_max(val, validator_max: NumberValidator):
    with pytest.raises(ValueError) as validation_failure:
        validator_max.validate_coerce(val)

    assert 'in the interval [-inf, 2.0]' in str(validation_failure.value)

# Array ok
# --------
# ### Acceptance ###
@pytest.mark.parametrize('val',
                         [1.0, 0.0, 1, 0.4])
def test_acceptance_aok_scalars(val, validator_aok: NumberValidator):
    assert validator_aok.validate_coerce(val) == val

@pytest.mark.parametrize('val',
                         [[1.0, 0.0], [1], [-0.1234, .41, -1.0]])
def test_acceptance_aok_list(val, validator_aok: NumberValidator):
    assert np.array_equal(validator_aok.validate_coerce(val), np.array(val, dtype='float'))

# ### Coerce ###
#     Coerced to general consistent numeric type
@pytest.mark.parametrize('val,expected',
                         [([1.0, 0], np.array([1.0, 0.0])),
                          (np.array([1, -1]), np.array([1.0, -1.0])),
                          ([-0.1234, 0, -1], np.array([-0.1234, 0.0, -1.0]))])
def test_coercion_aok_list(val, expected, validator_aok: NumberValidator):
    v = validator_aok.validate_coerce(val)
    assert isinstance(v, np.ndarray)
    assert v.dtype == 'float'
    assert np.array_equal(v, expected)

# ### Rejection ###
#
@pytest.mark.parametrize('val',
                         [['a', 4]])
def test_rejection_aok(val, validator_aok: NumberValidator):
    with pytest.raises(ValueError) as validation_failure:
        validator_aok.validate_coerce(val)

    assert 'Invalid value' in str(validation_failure.value)

# ### Rejection by element ###
@pytest.mark.parametrize('val',
                         [[-1.6, 0.0], [1, 1.5, 2], [-0.1234, .41, np.nan],
                          [0, np.inf], [0, -np.inf]])
def test_rejection_aok_min_max(val, validator_aok: NumberValidator):
    with pytest.raises(ValueError) as validation_failure:
        validator_aok.validate_coerce(val)

    assert 'Invalid element(s)' in str(validation_failure.value)
    assert 'in the interval [-1, 1.5]' in str(validation_failure.value)


"""
This is a procedural interface to the matplotlib object-oriented
plotting library.

The following plotting commands are provided; the majority have
MATLAB |reg| [*]_ analogs and similar arguments.

.. |reg| unicode:: 0xAE

_Plotting commands
  acorr     - plot the autocorrelation function
  annotate  - annotate something in the figure
  arrow     - add an arrow to the axes
  axes      - Create a new axes
  axhline   - draw a horizontal line across axes
  axvline   - draw a vertical line across axes
  axhspan   - draw a horizontal bar across axes
  axvspan   - draw a vertical bar across axes
  axis      - Set or return the current axis limits
  autoscale - turn axis autoscaling on or off, and apply it
  bar       - make a bar chart
  barh      - a horizontal bar chart
  broken_barh - a set of horizontal bars with gaps
  box       - set the axes frame on/off state
  boxplot   - make a box and whisker plot
  violinplot - make a violin plot
  cla       - clear current axes
  clabel    - label a contour plot
  clf       - clear a figure window
  clim      - adjust the color limits of the current image
  close     - close a figure window
  colorbar  - add a colorbar to the current figure
  cohere    - make a plot of coherence
  contour   - make a contour plot
  contourf  - make a filled contour plot
  csd       - make a plot of cross spectral density
  delaxes   - delete an axes from the current figure
  draw      - Force a redraw of the current figure
  errorbar  - make an errorbar graph
  figlegend - make legend on the figure rather than the axes
  figimage  - make a figure image
  figtext   - add text in figure coords
  figure   - create or change active figure
  fill     - make filled polygons
  findobj  - recursively find all objects matching some criteria
  gca      - return the current axes
  gcf      - return the current figure
  gci      - get the current image, or None
  getp      - get a graphics property
  grid     - set whether gridding is on
  hist     - make a histogram
  hold     - set the axes hold state
  ioff     - turn interaction mode off
  ion      - turn interaction mode on
  isinteractive - return True if interaction mode is on
  imread   - load image file into array
  imsave   - save array as an image file
  imshow   - plot image data
  ishold   - return the hold state of the current axes
  legend   - make an axes legend
  locator_params - adjust parameters used in locating axis ticks
  loglog   - a log log plot
  matshow  - display a matrix in a new figure preserving aspect
  margins  - set margins used in autoscaling
  pause    - pause for a specified interval
  pcolor   - make a pseudocolor plot
  pcolormesh - make a pseudocolor plot using a quadrilateral mesh
  pie      - make a pie chart
  plot     - make a line plot
  plot_date - plot dates
  plotfile  - plot column data from an ASCII tab/space/comma delimited file
  pie      - pie charts
  polar    - make a polar plot on a PolarAxes
  psd      - make a plot of power spectral density
  quiver   - make a direction field (arrows) plot
  rc       - control the default params
  rgrids   - customize the radial grids and labels for polar
  savefig  - save the current figure
  scatter  - make a scatter plot
  setp      - set a graphics property
  semilogx - log x axis
  semilogy - log y axis
  show     - show the figures
  specgram - a spectrogram plot
  spy      - plot sparsity pattern using markers or image
  stem     - make a stem plot
  subplot  - make one subplot (numrows, numcols, axesnum)
  subplots - make a figure with a set of (numrows, numcols) subplots
  subplots_adjust - change the params controlling the subplot positions of current figure
  subplot_tool - launch the subplot configuration tool
  suptitle   - add a figure title
  table    - add a table to the plot
  text     - add some text at location x,y to the current axes
  thetagrids - customize the radial theta grids and labels for polar
  tick_params - control the appearance of ticks and tick labels
  ticklabel_format - control the format of tick labels
  title    - add a title to the current axes
  tricontour - make a contour plot on a triangular grid
  tricontourf - make a filled contour plot on a triangular grid
  tripcolor - make a pseudocolor plot on a triangular grid
  triplot - plot a triangular grid
  xcorr   - plot the autocorrelation function of x and y
  xlim     - set/get the xlimits
  ylim     - set/get the ylimits
  xticks   - set/get the xticks
  yticks   - set/get the yticks
  xlabel   - add an xlabel to the current axes
  ylabel   - add a ylabel to the current axes

  autumn - set the default colormap to autumn
  bone   - set the default colormap to bone
  cool   - set the default colormap to cool
  copper - set the default colormap to copper
  flag   - set the default colormap to flag
  gray   - set the default colormap to gray
  hot    - set the default colormap to hot
  hsv    - set the default colormap to hsv
  jet    - set the default colormap to jet
  pink   - set the default colormap to pink
  prism  - set the default colormap to prism
  spring - set the default colormap to spring
  summer - set the default colormap to summer
  winter - set the default colormap to winter
  spectral - set the default colormap to spectral

_Event handling

  connect - register an event handler
  disconnect - remove a connected event handler

_Matrix commands

  cumprod   - the cumulative product along a dimension
  cumsum    - the cumulative sum along a dimension
  detrend   - remove the mean or besdt fit line from an array
  diag      - the k-th diagonal of matrix
  diff      - the n-th differnce of an array
  eig       - the eigenvalues and eigen vectors of v
  eye       - a matrix where the k-th diagonal is ones, else zero
  find      - return the indices where a condition is nonzero
  fliplr    - flip the rows of a matrix up/down
  flipud    - flip the columns of a matrix left/right
  linspace  - a linear spaced vector of N values from min to max inclusive
  logspace  - a log spaced vector of N values from min to max inclusive
  meshgrid  - repeat x and y to make regular matrices
  ones      - an array of ones
  rand      - an array from the uniform distribution [0,1]
  randn     - an array from the normal distribution
  rot90     - rotate matrix k*90 degress counterclockwise
  squeeze   - squeeze an array removing any dimensions of length 1
  tri       - a triangular matrix
  tril      - a lower triangular matrix
  triu      - an upper triangular matrix
  vander    - the Vandermonde matrix of vector x
  svd       - singular value decomposition
  zeros     - a matrix of zeros

_Probability

  normpdf   - The Gaussian probability density function
  rand      - random numbers from the uniform distribution
  randn     - random numbers from the normal distribution

_Statistics

  amax      - the maximum along dimension m
  amin      - the minimum along dimension m
  corrcoef  - correlation coefficient
  cov       - covariance matrix
  mean      - the mean along dimension m
  median    - the median along dimension m
  norm      - the norm of vector x
  prod      - the product along dimension m
  ptp       - the max-min along dimension m
  std       - the standard deviation along dimension m
  asum      - the sum along dimension m
  ksdensity - the kernel density estimate

_Time series analysis

  bartlett  - M-point Bartlett window
  blackman  - M-point Blackman window
  cohere    - the coherence using average periodiogram
  csd       - the cross spectral density using average periodiogram
  fft       - the fast Fourier transform of vector x
  hamming   - M-point Hamming window
  hanning   - M-point Hanning window
  hist      - compute the histogram of x
  kaiser    - M length Kaiser window
  psd       - the power spectral density using average periodiogram
  sinc      - the sinc function of array x

_Dates

  date2num  - convert python datetimes to numeric representation
  drange    - create an array of numbers for date plots
  num2date  - convert numeric type (float days since 0001) to datetime

_Other

  angle     - the angle of a complex array
  griddata  - interpolate irregularly distributed data to a regular grid
  load      - Deprecated--please use loadtxt.
  loadtxt   - load ASCII data into array.
  polyfit   - fit x, y to an n-th order polynomial
  polyval   - evaluate an n-th order polynomial
  roots     - the roots of the polynomial coefficients in p
  save      - Deprecated--please use savetxt.
  savetxt   - save an array to an ASCII file.
  trapz     - trapezoidal integration

__end

.. [*] MATLAB is a registered trademark of The MathWorks, Inc.

"""
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import six

import sys, warnings

from matplotlib.cbook import flatten, is_string_like, exception_to_str, \
     silent_list, iterable, dedent

import matplotlib as mpl
# make mpl.finance module available for backwards compatability, in case folks
# using pylab interface depended on not having to import it
import matplotlib.finance

from matplotlib.dates import date2num, num2date,\
        datestr2num, strpdate2num, drange,\
        epoch2num, num2epoch, mx2num,\
        DateFormatter, IndexDateFormatter, DateLocator,\
        RRuleLocator, YearLocator, MonthLocator, WeekdayLocator,\
        DayLocator, HourLocator, MinuteLocator, SecondLocator,\
        rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY, MONTHLY,\
        WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY, relativedelta

import matplotlib.dates  # Do we need this at all?

# bring all the  symbols in so folks can import them from
# pylab in one fell swoop

## We are still importing too many things from mlab; more cleanup is needed.

from matplotlib.mlab import griddata, stineman_interp, slopes, \
    inside_poly, poly_below, poly_between, \
    is_closed_polygon, path_length, distances_along_curve, vector_lengths

from matplotlib.mlab import window_hanning, window_none,  detrend, demean, \
     detrend_mean, detrend_none, detrend_linear, entropy, normpdf, \
     find, longest_contiguous_ones, longest_ones, prepca, \
     prctile, prctile_rank, \
     center_matrix, rk4, bivariate_normal, get_xyz_where, \
     get_sparse_matrix, dist, \
     dist_point_to_segment, segments_intersect, fftsurr, movavg, \
     exp_safe, \
     amap, rms_flat, l1norm, l2norm, norm_flat, frange,  identity, \
     base_repr, binary_repr, log2, ispower2, \
     rec_append_fields, rec_drop_fields, rec_join, csv2rec, rec2csv, isvector

import matplotlib.mlab as mlab
import matplotlib.cbook as cbook

from numpy import *
from numpy.fft import *
from numpy.random import *
from numpy.linalg import *

from matplotlib.pyplot import *

# provide the recommended module abbrevs in the pylab namespace
import matplotlib.pyplot as plt
import numpy as np
import numpy.ma as ma

# don't let numpy's datetime hide stdlib
import datetime

# This is needed, or bytes will be numpy.random.bytes from
# "from numpy.random import *" above
bytes = __builtins__['bytes']


#!/usr/bin/env python
# coding: utf-8

# # Project 2: Breakout Strategy
# ## Instructions
# Each problem consists of a function to implement and instructions on how to implement the function.  The parts of the function that need to be implemented are marked with a `# TODO` comment. After implementing the function, run the cell to test it against the unit tests we've provided. For each problem, we provide one or more unit tests from our `project_tests` package. These unit tests won't tell you if your answer is correct, but will warn you of any major errors. Your code will be checked for the correct solution when you submit it to Udacity.
#
# ## Packages
# When you implement the functions, you'll only need to you use the packages you've used in the classroom, like [Pandas](https://pandas.pydata.org/) and [Numpy](http://www.numpy.org/). These packages will be imported for you. We recommend you don't add any import statements, otherwise the grader might not be able to run your code.
#
# The other packages that we're importing are `helper`, `project_helper`, and `project_tests`. These are custom packages built to help you solve the problems.  The `helper` and `project_helper` module contains utility functions and graph functions. The `project_tests` contains the unit tests for all the problems.
#
# ### Install Packages

# In[1]:

import sys
get_ipython().system('{sys.executable} -m pip install -r requirements.txt')

# ### Load Packages

# In[2]:

import pandas as pd
import numpy as np
import helper
import project_helper
import project_tests

# ## Market Data
# ### Load Data
# While using real data will give you hands on experience, it's doesn't cover all the topics we try to condense in one project. We'll solve this by creating new stocks. We've create a scenario where companies mining [Terbium](https://en.wikipedia.org/wiki/Terbium) are making huge profits. All the companies in this sector of the market are made up. They represent a sector with large growth that will be used for demonstration latter in this project.

# In[3]:

df_original = pd.read_csv('../../data/project_2/eod-quotemedia.csv', parse_dates=['date'], index_col=False)

# Add TB sector to the market
df = df_original
df = pd.concat([df] + project_helper.generate_tb_sector(df[df['ticker'] == 'AAPL']['date']), ignore_index=True)

close = df.reset_index().pivot(index='date', columns='ticker', values='adj_close')
high = df.reset_index().pivot(index='date', columns='ticker', values='adj_high')
low = df.reset_index().pivot(index='date', columns='ticker', values='adj_low')

print('Loaded Data')

# ### View Data
# To see what one of these 2-d matrices looks like, let's take a look at the closing prices matrix.

# In[4]:

close

# ### Stock Example
# Let's see what a single stock looks like from the closing prices. For this example and future display examples in this project, we'll use Apple's stock (AAPL). If we tried to graph all the stocks, it would be too much information.

# In[5]:

apple_ticker = 'AAPL'
project_helper.plot_stock(close[apple_ticker], '{} Stock'.format(apple_ticker))

# ## The Alpha Research Process
#
# In this project you will code and evaluate a "breakout" signal. It is important to understand where these steps fit in the alpha research workflow. The signal-to-noise ratio in trading signals is very low and, as such, it is very easy to fall into the trap of _overfitting_ to noise. It is therefore inadvisable to jump right into signal coding. To help mitigate overfitting, it is best to start with a general observation and hypothesis; i.e., you should be able to answer the following question _before_ you touch any data:
#
# > What feature of markets or investor behaviour would lead to a persistent anomaly that my signal will try to use?
#
# Ideally the assumptions behind the hypothesis will be testable _before_ you actually code and evaluate the signal itself. The workflow therefore is as follows:
#
# ![image](images/alpha_steps.png)
#
# In this project, we assume that the first three steps area done ("observe & research", "form hypothesis", "validate hypothesis"). The hypothesis you'll be using for this project is the following:
# - In the absence of news or significant investor trading interest, stocks oscillate in a range.
# - Traders seek to capitalize on this range-bound behaviour periodically by selling/shorting at the top of the range and buying/covering at the bottom of the range. This behaviour reinforces the existence of the range.
# - When stocks break out of the range, due to, e.g., a significant news release or from market pressure from a large investor:
#     - the liquidity traders who have been providing liquidity at the bounds of the range seek to cover their positions to mitigate losses, thus magnifying the move out of the range, _and_
#     - the move out of the range attracts other investor interest; these investors, due to the behavioural bias of _herding_ (e.g., [Herd Behavior](https://www.investopedia.com/university/behavioral_finance/behavioral8.asp)) build positions which favor continuation of the trend.
#
#
# Using this hypothesis, let start coding..
# ## Compute the Highs and Lows in a Window
# You'll use the price highs and lows as an indicator for the breakout strategy. In this section, implement `get_high_lows_lookback` to get the maximum high price and minimum low price over a window of days. The variable `lookback_days` contains the number of days to look in the past. Make sure this doesn't include the current day.

# In[6]:

def get_high_lows_lookback(high, low, lookback_days):
    high_s=high.shift(1)
    low_s=low.shift(1)
    lookback_high=high_s.rolling(lookback_days,min_periods=lookback_days).max()
    lookback_low=low_s.rolling(lookback_days,min_periods=lookback_days).min()
    """
    Get the highs and lows in a lookback window.

    Parameters
    ----------
    high : DataFrame
        High price for each ticker and date
    low : DataFrame
        Low price for each ticker and date
    lookback_days : int
        The number of days to look back

    Returns
    -------
    lookback_high : DataFrame
        Lookback high price for each ticker and date
    lookback_low : DataFrame
        Lookback low price for each ticker and date
    """
    #TODO: Implement function

    return lookback_high, lookback_low

project_tests.test_get_high_lows_lookback(get_high_lows_lookback)

# ### View Data
# Let's use your implementation of `get_high_lows_lookback` to get the highs and lows for the past 50 days and compare it to it their respective stock.  Just like last time, we'll use Apple's stock as the example to look at.

# In[7]:

lookback_days = 50
lookback_high, lookback_low = get_high_lows_lookback(high, low, lookback_days)
project_helper.plot_high_low(
    close[apple_ticker],
    lookback_high[apple_ticker],
    lookback_low[apple_ticker],
    'High and Low of {} Stock'.format(apple_ticker))

# ## Compute Long and Short Signals
# Using the generated indicator of highs and lows, create long and short signals using a breakout strategy. Implement `get_long_short` to generate the following signals:
#
# | Signal | Condition |
# |----|------|
# | -1 | Low > Close Price |
# | 1  | High < Close Price |
# | 0  | Otherwise |
#
# In this chart, **Close Price** is the `close` parameter. **Low** and **High** are the values generated from `get_high_lows_lookback`, the `lookback_high` and `lookback_low` parameters.

# In[8]:

def get_long_short(close, lookback_high, lookback_low):

    closed=close.copy()

    closed_high=(lookback_high.fillna(0)-closed)
    z=closed_high!= 0-closed
    clear=closed_high.where(z,0)
    y=clear<=0
    n=clear.where(y,0)
    x=clear>=0
    high=n.where(x,1)
    close_high=high.astype(int)

    closed_low=(closed-lookback_low.fillna(0))
    t=closed_low<=0
    f=closed_low>=0 #lowest
    g=closed_low!=closed

    low_var=closed_low.where(g,0)
    low_f=low_var.where(t,0)
    low_df=low_f.where(f,-1)
    close_low=low_df.astype(int)
    long_short=close_high+close_low

    """
    Generate the signals long, short, and do nothing.

    Parameters
    ----------
    close : DataFrame
        Close price for each ticker and date
    lookback_high : DataFrame
        Lookback high price for each ticker and date
    lookback_low : DataFrame
        Lookback low price for each ticker and date

    Returns
    -------
    long_short : DataFrame
        The long, short, and do nothing signals for each ticker and date
    """
    #TODO: Implement function

    return long_short

project_tests.test_get_long_short(get_long_short)

# ### View Data
# Let's compare the signals you generated against the close prices. This chart will show a lot of signals. Too many in fact. We'll talk about filtering the redundant signals in the next problem.

# In[9]:

signal = get_long_short(close, lookback_high, lookback_low)
project_helper.plot_signal(
    close[apple_ticker],
    signal[apple_ticker],
    'Long and Short of {} Stock'.format(apple_ticker))

# ## Filter Signals
# That was a lot of repeated signals! If we're already shorting a stock, having an additional signal to short a stock isn't helpful for this strategy. This also applies to additional long signals when the last signal was long.
#
# Implement `filter_signals` to filter out repeated long or short signals within the `lookahead_days`. If the previous signal was the same, change the signal to `0` (do nothing signal). For example, say you have a single stock time series that is
#
# `[1, 0, 1, 0, 1, 0, -1, -1]`
#
# Running `filter_signals` with a lookahead of 3 days should turn those signals into
#
# `[1, 0, 0, 0, 1, 0, -1, 0]`
#
# To help you implement the function, we have provided you with the `clear_signals` function. This will remove all signals within a window after the last signal. For example, say you're using a windows size of 3 with `clear_signals`. It would turn the Series of long signals
#
# `[0, 1, 0, 0, 1, 1, 0, 1, 0]`
#
# into
#
# `[0, 1, 0, 0, 0, 1, 0, 0, 0]`
#
# `clear_signals` only takes a Series of the same type of signals, where `1` is the signal and `0` is no signal. It can't take a mix of long and short signals. Using this function, implement `filter_signals`.
#
# For implementing `filter_signals`, we don't reccommend you try to find a vectorized solution. Instead, you should use the [`iterrows`](https://pandas.pydata.org/pandas-docs/version/0.21/generated/pandas.DataFrame.iterrows.html) over each column.

# In[10]:

def clear_signals(signals, window_size):
    """
    Clear out signals in a Series of just long or short signals.

    Remove the number of signals down to 1 within the window size time period.

    Parameters
    ----------
    signals : Pandas Series
        The long, short, or do nothing signals
    window_size : int
        The number of days to have a single signal

    Returns
    -------
    signals : Pandas Series
        Signals with the signals removed from the window size
    """
    # Start with buffer of window size
    # This handles the edge case of calculating past_signal in the beginning
    clean_signals = [0]*window_size

    for signal_i, current_signal in enumerate(signals):
        # Check if there was a signal in the past window_size of days
        has_past_signal = bool(sum(clean_signals[signal_i:signal_i+window_size]))
        # Use the current signal if there's no past signal, else 0/False
        clean_signals.append(not has_past_signal and current_signal)

    # Remove buffer
    clean_signals = clean_signals[window_size:]

    # Return the signals as a Series of Ints
    return pd.Series(np.array(clean_signals).astype(np.int), signals.index)

def filter_signals(signal, lookahead_days):
    z=signal==-1
    y=signal== 1
    sig_l=signal.where(z,0)
    sig_s=signal.where(y,0)

    for column in sig_l:
        sig_l[column]=clear_signals(sig_l[column], lookahead_days)

    for column in sig_s:
        sig_s[column]=clear_signals(sig_s[column],lookahead_days)

    filtered_signal=sig_l+sig_s

    """
    Filter out signals in a DataFrame.

    Parameters
    ----------
    signal : DataFrame
        The long, short, and do nothing signals for each ticker and date
    lookahead_days : int
        The number of days to look ahead

    Returns
    -------
    filtered_signal : DataFrame
        The filtered long, short, and do nothing signals for each ticker and date
    """
    #TODO: Implement function

    return filtered_signal

project_tests.test_filter_signals(filter_signals)

# ### View Data
# Let's view the same chart as before, but with the redundant signals removed.

# In[11]:

signal_5 = filter_signals(signal, 5)
signal_10 = filter_signals(signal, 10)
signal_20 = filter_signals(signal, 20)
for signal_data, signal_days in [(signal_5, 5), (signal_10, 10), (signal_20, 20)]:
    project_helper.plot_signal(
        close[apple_ticker],
        signal_data[apple_ticker],
        'Long and Short of {} Stock with {} day signal window'.format(apple_ticker, signal_days))

# ## Lookahead Close Prices
# With the trading signal done, we can start working on evaluating how many days to short or long the stocks. In this problem, implement `get_lookahead_prices` to get the close price days ahead in time. You can get the number of days from the variable `lookahead_days`. We'll use the lookahead prices to calculate future returns in another problem.

# In[12]:

def get_lookahead_prices(close, lookahead_days):

    closed=close.copy()
    n=closed.shift(-lookahead_days)

    """
    Get the lookahead prices for `lookahead_days` number of days.

    Parameters
    ----------
    close : DataFrame
        Close price for each ticker and date
    lookahead_days : int
        The number of days to look ahead

    Returns
    -------
    lookahead_prices : DataFrame
        The lookahead prices for each ticker and date
    """
    #TODO: Implement function

    return n
#get_lookahead_prices(close, 2)
project_tests.test_get_lookahead_prices(get_lookahead_prices)

# ### View Data
# Using the `get_lookahead_prices` function, let's generate lookahead closing prices for 5, 10, and 20 days.
#
# Let's also chart a subsection of a few months of the Apple stock instead of years. This will allow you to view the differences between the 5, 10, and 20 day lookaheads. Otherwise, they will mesh together when looking at a chart that is zoomed out.

# In[13]:

lookahead_5 = get_lookahead_prices(close, 5)
lookahead_10 = get_lookahead_prices(close, 10)
lookahead_20 = get_lookahead_prices(close, 20)
project_helper.plot_lookahead_prices(
    close[apple_ticker].iloc[150:250],
    [
        (lookahead_5[apple_ticker].iloc[150:250], 5),
        (lookahead_10[apple_ticker].iloc[150:250], 10),
        (lookahead_20[apple_ticker].iloc[150:250], 20)],
    '5, 10, and 20 day Lookahead Prices for Slice of {} Stock'.format(apple_ticker))

# ## Lookahead Price Returns
# Implement `get_return_lookahead` to generate the log price return between the closing price and the lookahead price.

# In[14]:

def get_return_lookahead(close, lookahead_prices):

    ret=np.log(lookahead_prices/close)
    """
    Calculate the log returns from the lookahead days to the signal day.

    Parameters
    ----------
    close : DataFrame
        Close price for each ticker and date
    lookahead_prices : DataFrame
        The lookahead prices for each ticker and date

    Returns
    -------
    lookahead_returns : DataFrame
        The lookahead log returns for each ticker and date
    """
    #TODO: Implement function

    return ret

project_tests.test_get_return_lookahead(get_return_lookahead)

# ### View Data
# Using the same lookahead prices and same subsection of the Apple stock from the previous problem, we'll view the lookahead returns.
#
# In order to view price returns on the same chart as the stock, a second y-axis will be added. When viewing this chart, the axis for the price of the stock will be on the left side, like previous charts. The axis for price returns will be located on the right side.

# In[15]:

price_return_5 = get_return_lookahead(close, lookahead_5)
price_return_10 = get_return_lookahead(close, lookahead_10)
price_return_20 = get_return_lookahead(close, lookahead_20)
project_helper.plot_price_returns(
    close[apple_ticker].iloc[150:250],
    [
        (price_return_5[apple_ticker].iloc[150:250], 5),
        (price_return_10[apple_ticker].iloc[150:250], 10),
        (price_return_20[apple_ticker].iloc[150:250], 20)],
    '5, 10, and 20 day Lookahead Returns for Slice {} Stock'.format(apple_ticker))

# ## Compute the Signal Return
# Using the price returns generate the signal returns.

# In[16]:

def get_signal_return(signal, lookahead_returns):
    ret=signal*lookahead_returns
    """
    Compute the signal returns.

    Parameters
    ----------
    signal : DataFrame
        The long, short, and do nothing signals for each ticker and date
    lookahead_returns : DataFrame
        The lookahead log returns for each ticker and date

    Returns
    -------
    signal_return : DataFrame
        Signal returns for each ticker and date
    """
    #TODO: Implement function

    return ret

project_tests.test_get_signal_return(get_signal_return)

# ### View Data
# Let's continue using the previous lookahead prices to view the signal returns. Just like before, the axis for the signal returns is on the right side of the chart.

# In[17]:

title_string = '{} day LookaheadSignal Returns for {} Stock'
signal_return_5 = get_signal_return(signal_5, price_return_5)
signal_return_10 = get_signal_return(signal_10, price_return_10)
signal_return_20 = get_signal_return(signal_20, price_return_20)
project_helper.plot_signal_returns(
    close[apple_ticker],
    [
        (signal_return_5[apple_ticker], signal_5[apple_ticker], 5),
        (signal_return_10[apple_ticker], signal_10[apple_ticker], 10),
        (signal_return_20[apple_ticker], signal_20[apple_ticker], 20)],
    [title_string.format(5, apple_ticker), title_string.format(10, apple_ticker), title_string.format(20, apple_ticker)])

# ## Test for Significance
# ### Histogram
# Let's plot a histogram of the signal return values.

# In[18]:

project_helper.plot_signal_histograms(
    [signal_return_5, signal_return_10, signal_return_20],
    'Signal Return',
    ('5 Days', '10 Days', '20 Days'))

# ### Question: What do the histograms tell you about the signal returns?

# *#TODO: Put Answer In this Cell*
#
#         The distribution appears to have a slight left skew and when compared with a normal distribution the outliers can be observed to be located in the left (positive) tail of the distribution.The signal returns if cleared of outliers can thus be said to be normally distributed.

# ## Outliers
# You might have noticed the outliers in the 10 and 20 day histograms. To better visualize the outliers, let's compare the 5, 10, and 20 day signals returns to normal distributions with the same mean and deviation for each signal return distributions.

# In[19]:

project_helper.plot_signal_to_normal_histograms(
    [signal_return_5, signal_return_10, signal_return_20],
    'Signal Return',
    ('5 Days', '10 Days', '20 Days'))

# ## Kolmogorov-Smirnov Test
# While you can see the outliers in the histogram, we need to find the stocks that are causing these outlying returns. We'll use the Kolmogorov-Smirnov Test or KS-Test. This test will be applied to teach ticker's signal returns where a long or short signal exits.

# In[20]:

# Filter out returns that don't have a long or short signal.
long_short_signal_returns_5 = signal_return_5[signal_5 != 0].stack()
long_short_signal_returns_10 = signal_return_10[signal_10 != 0].stack()
long_short_signal_returns_20 = signal_return_20[signal_20 != 0].stack()

# Get just ticker and signal return
long_short_signal_returns_5 = long_short_signal_returns_5.reset_index().iloc[:, [1,2]]
long_short_signal_returns_5.columns = ['ticker', 'signal_return']
long_short_signal_returns_10 = long_short_signal_returns_10.reset_index().iloc[:, [1,2]]
long_short_signal_returns_10.columns = ['ticker', 'signal_return']
long_short_signal_returns_20 = long_short_signal_returns_20.reset_index().iloc[:, [1,2]]
long_short_signal_returns_20.columns = ['ticker', 'signal_return']

# View some of the data
long_short_signal_returns_5.head(10)

# This gives you the data to use in the KS-Test.
#
# Now it's time to implement the function `calculate_kstest` to use Kolmogorov-Smirnov test (KS test) between a distribution of stock returns (the input dataframe in this case) and each stock's signal returns. Run KS test on a normal distribution against each stock's signal returns. Use [`scipy.stats.kstest`](https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.stats.kstest.html#scipy-stats-kstest) perform the KS test. When calculating the standard deviation of the signal returns, make sure to set the delta degrees of freedom to 0.
#
# For this function, we don't reccommend you try to find a vectorized solution. Instead, you should iterate over the [`groupby`](https://pandas.pydata.org/pandas-docs/version/0.21/generated/pandas.DataFrame.groupby.html) function.

# In[21]:

from scipy.stats import kstest

def calculate_kstest(long_short_signal_returns):

    copy_n=long_short_signal_returns.copy()

    group_signal=copy_n.groupby(['ticker'])

    k_s=[]
    p_s=[]
    indexes=[]

    for i,r in group_signal:
        mu=np.mean(copy_n['signal_return'])
        std=np.std(copy_n['signal_return'],ddof=0)
        data=r['signal_return']

        k,p=kstest(data,'norm',args=(mu,std))
        k_s.append(k)
        p_s.append(p)
        indexes.append(i)

    """
    Calculate the KS-Test against the signal returns with a long or short signal.

    Parameters
    ----------
    long_short_signal_returns : DataFrame
        The signal returns which have a signal.
        This DataFrame contains two columns, "ticker" and "signal_return"

    Returns
    -------
    ks_values : Pandas Series
        KS static for all the tickers
    p_values : Pandas Series
        P value for all the tickers
    """
    #TODO: Implement function
    return pd.Series(k_s,index=indexes),pd.Series(p_s,index=indexes)
#question asked on the mentor Q and A platform but the code provided in the answer was not used.
project_tests.test_calculate_kstest(calculate_kstest)

# ### View Data
# Using the signal returns we created above, let's calculate the ks and p values.

# In[22]:

ks_values_5, p_values_5 = calculate_kstest(long_short_signal_returns_5)
ks_values_10, p_values_10 = calculate_kstest(long_short_signal_returns_10)
ks_values_20, p_values_20 = calculate_kstest(long_short_signal_returns_20)

print('ks_values_5')
print(ks_values_5.head(10))
print('p_values_5')
print(p_values_5.head(10))

# ## Find Outliers
# With the ks and p values calculate, let's find which symbols are the outliers. Implement the `find_outliers` function to find the following outliers:
# - Symbols that pass the null hypothesis with a p-value less than `pvalue_threshold`.
# - Symbols that with a KS value above `ks_threshold`.

# In[23]:

def find_outliers(ks_values, p_values, ks_threshold, pvalue_threshold=0.05):
    k_s=set()
    p_s=set()
    for i in ks_values.index:
        if ks_values[i]>ks_threshold:
            k_s.add(i)
        if p_values[i]<pvalue_threshold:
            p_s.add(i)
    """
    Find outlying symbols using KS values and P-values

    Parameters
    ----------
    ks_values : Pandas Series
        KS static for all the tickers
    p_values : Pandas Series
        P value for all the tickers
    ks_threshold : float
        The threshold for the KS statistic
    pvalue_threshold : float
        The threshold for the p-value

    Returns
    -------
    outliers : set of str
        Symbols that are outliers
    """
    #TODO: Implement function

    return k_s.intersection(p_s)

project_tests.test_find_outliers(find_outliers)

# ### View Data
# Using the `find_outliers` function you implemented, let's see what we found.

# In[24]:

ks_threshold = 0.8
outliers_5 = find_outliers(ks_values_5, p_values_5, ks_threshold)
outliers_10 = find_outliers(ks_values_10, p_values_10, ks_threshold)
outliers_20 = find_outliers(ks_values_20, p_values_20, ks_threshold)

outlier_tickers = outliers_5.union(outliers_10).union(outliers_20)
print('{} Outliers Found:\n{}'.format(len(outlier_tickers), ', '.join(list(outlier_tickers))))

# ### Show Significance without Outliers
# Let's compare the 5, 10, and 20 day signals returns without outliers to normal distributions. Also, let's see how the P-Value has changed with the outliers removed.

# In[25]:

good_tickers = list(set(close.columns) - outlier_tickers)

project_helper.plot_signal_to_normal_histograms(
    [signal_return_5[good_tickers], signal_return_10[good_tickers], signal_return_20[good_tickers]],
    'Signal Return Without Outliers',
    ('5 Days', '10 Days', '20 Days'))

# That's more like it! The returns are closer to a normal distribution. You have finished the research phase of a Breakout Strategy. You can now submit your project.
# ## Submission
# Now that you're done with the project, it's time to submit it. Click the submit button in the bottom right. One of our reviewers will give you feedback on your project with a pass or not passed grade. You can continue to the next section while you wait for feedback.


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

"""Set seed for multi-agent experiments.

Author: Yoshinari Motokawa <yoshinari.moto@fuji.waseda.jp>
"""

import random

import numpy as np
import torch

def set_seed(seed: int = 921):
    torch.manual_seed(seed)
    np.random.seed(seed)
    random.seed(seed)


![Callysto.ca Banner](https://github.com/callysto/curriculum-notebooks/blob/master/callysto-notebook-banner-top.jpg?raw=true)

(Click **Cell** > **Run All** before proceeding.)

%matplotlib inline

#----------
#Import modules and packages
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import random

#----------

#import ipywidgets as widgets
#import random

#This function produces a multiple choice form with four options
def multiple_choice(option_1, option_2, option_3, option_4):
    option_list = [option_1, option_2, option_3, option_4]
    answer = option_list[0]
    letters = ["(A) ", "(B) ", "(C) ", "(D) "]

    #Boldface letters at the beginning of each option
    start_bold = "\033[1m"; end_bold = "\033[0;0m"

    #Randomly shuffle the options
    random.shuffle(option_list)

    #Prints the letters (A) to (D) in sequence with randomly chosen options
    for i in range(4):
        option_text = option_list.pop()
        print(start_bold + letters[i] + end_bold + option_text)

        #Stores the correct answer
        if option_text == answer:
            letter_answer = letters[i]

    button1 = widgets.Button(description="(A)"); button2 = widgets.Button(description="(B)")
    button3 = widgets.Button(description="(C)"); button4 = widgets.Button(description="(D)")

    button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Whitesmoke'
    button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Whitesmoke'

    container = widgets.HBox(children=[button1,button2,button3,button4])
    display(container)
    print(" ", end='\r')

    def on_button1_clicked(b):
        if "(A) " == letter_answer:
            print("Correct!    ", end='\r')
            button1.style.button_color = 'Moccasin'; button2.style.button_color = 'Whitesmoke'
            button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Whitesmoke'
        else:
            print("Try again.", end='\r')
            button1.style.button_color = 'Lightgray'; button2.style.button_color = 'Whitesmoke'
            button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Whitesmoke'

    def on_button2_clicked(b):
        if "(B) " == letter_answer:
            print("Correct!    ", end='\r')
            button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Moccasin'
            button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Whitesmoke'
        else:
            print("Try again.", end='\r')
            button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Lightgray'
            button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Whitesmoke'

    def on_button3_clicked(b):
        if "(C) " == letter_answer:
            print("Correct!    ", end='\r')
            button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Whitesmoke'
            button3.style.button_color = 'Moccasin'; button4.style.button_color = 'Whitesmoke'
        else:
            print("Try again.", end='\r')
            button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Whitesmoke'
            button3.style.button_color = 'Lightgray'; button4.style.button_color = 'Whitesmoke'

    def on_button4_clicked(b):
        if "(D) " == letter_answer:
            print("Correct!    ", end='\r')
            button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Whitesmoke'
            button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Moccasin'
        else:
            print("Try again.", end='\r')
            button1.style.button_color = 'Whitesmoke'; button2.style.button_color = 'Whitesmoke'
            button3.style.button_color = 'Whitesmoke'; button4.style.button_color = 'Lightgray'

    button1.on_click(on_button1_clicked); button2.on_click(on_button2_clicked)
    button3.on_click(on_button3_clicked); button4.on_click(on_button4_clicked)

# Static and Kinetic Friction

## Introduction

**Friction** is the name given to the force that resists the relative motion of one object as it slides against another. Most surfaces are rough and uneven. Even smooth surfaces, such as a polished mirror, can appear bumpy under a microscope. The bumps on these surfaces interlock as they rub against one another, which prevents them from sliding freely.

The more an object presses into a surface, the more the surface pushes back against the object. The force pushing back against the object is called the **normal force**, **$F_{n}$** and it is always perpendicular to the surface. From the image above, we can imagine that the more two objects are pressed together, the more difficult it is for the interlocking points to lift up and slide passed one another. As a consequence, the friction force increases. A relationship therefore exists between the magnitude of the friction force and that of the normal force. This relationship is expressed by the following equation:

$$F_{f}=\mu F_{n}$$

where $F_{f}$ and $F_{n}$ are the magnitudes of the friction and normal forces respectively, and $\mu$ is the **coefficient of friction**. Here $\mu$ is the Greek letter $mu$.  The direction of the force of friction is parallel to the surface and opposite to the other forces acting on the object.

Use the slider below to observe the relationship between the normal force and the friction force. Pick any value for the coefficient of friction. Move the slider for the normal force back and forth to calculate the corresponding force of friction.

#import ipywidgets as widgets

coeff = widgets.FloatSlider(description="Coefficient",min=0.1,max=0.9)
normal_force = widgets.IntSlider(description="Normal force",min=5,max=50)

#Boldface letters at the beginning of each option
start_bold = "\033[1m"; end_bold = "\033[0;0m"

def f(coeff, normal_force):
    friction_force = coeff * normal_force
    print(start_bold + "Friction force = (coefficient of friction) X (normal force)" + end_bold)
    print("Friction force = {} X {} = {} N".format(coeff, normal_force, round(friction_force,1)))

out = widgets.interactive_output(f,{'coeff': coeff, 'normal_force': normal_force})

widgets.HBox([widgets.VBox([coeff, normal_force]), out])

**Question:** *What happens to the friction force when the normal force increases?*

#import ipywidgets as widgets

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = "The friction force increases."
option_2 = "The friction force decreases."
option_3 = "The friction force remains constant."
option_4 = "The friction force equals zero."

multiple_choice(option_1, option_2, option_3, option_4)

The force of friction felt by an object depends on whether the objects are in motion with respect to each other.  In general the force of friction felt by an object which is not moving with respect to another is stronger than the force of friction felt once it begins moving.

**Static friction** describes the friction force that acts between an object and a surface to prevent it from sliding when a force is applied to it. Static friction applies to objects that are stationary with respect to one another.

**Kinetic friction** describes the friction force that acts between an object and the surface it slides upon when a force is applied to it. Kinetic friction applies to objects that are in motion with respect to one another.

### Coefficients of Friction

Values for the coefficients of friction have been derived experimentally for various materials as they interact with one another. When we describe the friction acting on a stationary object, we must use the **coefficient of static friction, $\mu_{s}$**. When we describe the friction of a sliding object, we must use the **coefficient of kinetic friction, $\mu_{k}$**. Some values for the coefficients of static and kinetic friction are shown in the table below:

 Materials          | Coefficients of static friction ($\mu_{s}$)| Coefficients of kinetic friction ($\mu_{k}$)
 ---                | ---                                       | ---
 Steel on steel     | 0.7                                       | 0.6
 Glass on glass     | 0.9                                       | 0.4
 Wood on wood       | 0.4                                       | 0.2
 Rubber on concrete | 1.0                                       | 0.8

Use the slider again to observe the relationship between the coefficient of friction and the friction force. Pick any value for the normal force. Move the slider for the coefficient of friction back and forth to calculate the corresponding force of friction.

#import ipywidgets as widgets

coeff = widgets.FloatSlider(description="Coefficient",min=0.1,max=0.9)
normal_force = widgets.IntSlider(description="Normal force",min=5,max=50)

#Boldface letters at the beginning of each option
start_bold = "\033[1m"; end_bold = "\033[0;0m"

def f(coeff, normal_force):
    friction_force = coeff * normal_force
    print(start_bold + "Friction force = (coefficient of friction) X (normal force)" + end_bold)
    print("Friction force = {} X {} = {} N".format(coeff, normal_force, round(friction_force,1)))

out = widgets.interactive_output(f,{'coeff': coeff, 'normal_force': normal_force})

widgets.HBox([widgets.VBox([coeff, normal_force]), out])

**Question:** *What happens to the friction force when the coefficient of friction increases?*

#import ipywidgets as widgets

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = "The friction force increases."
option_2 = "The friction force decreases."
option_3 = "The friction force remains constant."
option_4 = "The friction force equals zero."

multiple_choice(option_1, option_2, option_3, option_4)

It is to be noted that the amount $\mu_s F_{n}$ is actually the **maximal value** for the magnitude of **static** friction $F_{f}$.  Assuming the forces acting on an object are insufficient to overcome this maximal value, the object will be stationary.  In this case, the actual magnitude of the force of static friction, $F_{f}$, will typically be less than maximal; it is exactly that amount required to have a net force of zero so that the object does not move.

### Solving Friction Problems

When solving a friction problem, it is useful to construct a free-body diagram. A **free-body diagram** is a simple graphical representation of an object and all the relevant forces acting upon it. An example of a free-body diagram is shown below:

* $F_{a}$ represents the **applied force**: the force acting in the direction of motion of the object.
* $F_{f}$ represents the **friction force**: the force acting in the direction opposite to the motion of the object.
* $mg$ represents the weight: the force of gravity acting on the object. Here, $m$ is the mass of the object, and $g$ is the gravitational acceleration directed downwards and of magnitude $g=9.8\:m/s^2$.
* $F_{n}$ represents the normal force: the force perpendicular to the surface pressing up against the object.

### Example
A 10 kg object is pushed across a flat horizontal surface with an applied force of 25 N. The same object is later pushed again with an applied force of 50 N. The coefficients of static and kinetic frictions are 0.40 and 0.30, respectively. Calculate the friction force ($F_{f}$) at each of the applied forces. Use the formula: $F_{f}=\mu F_{n}$.

**Step 1:** *Construct a free-body diagram*. The free-body diagram shown above may be used for this example.

**Step 2:** *Calculate the known forces*: **Recall:** The weight of the object, $mg$, is equal to the mass of the object multiplied by the acceleration due to gravity.

$$mg = (10 \times 9.8)\:N = 98\:N$$

Since there is no vertical acceleration on the object, the total vertical force must vanish so the magnitude of the normal force must be equal to that of the weight of the object ($F_{n} = mg$). Therefore,

$$F_{n} = mg = (10 \times 9.8)\:N = 98\:N$$

**Step 3:** *Determine the maximum static friction force*: Now that the normal force is known, we can calculate the maximum static friction force using the following equation:

$$F_{s}=\mu_{s} F_{n} = (0.40 \times 98)\:N = 39\:N$$

This means that the object will resist up to 39 N of applied force before it begins to move.

**Step 4:** *Determine the friction force at 25 N*: Since the applied force of 25 N is less than the maximum static friction force, the object will remain stationary. The friction will oppose the applied force up to 25 N. Therefore,

$$F_{f} = 25\:N$$

The direction of $F_{f}$ will be opposite to the direction of the applied force.

**Step 5:** *Determine the friction force at 50 N*: Since the applied force of 50 N is greater than the maximum static friction force, the object will begin to move. When in motion, the object is no longer being opposed by the static friction force. Instead it is being opposed by the kinetic friction force. We can calculate the kinetic friction force using the following equation:

$$F_{k}=\mu_{k} F_{n} = (0.30 \times 98)\:N = 29\:N$$

Therefore, the magnitude of the friction force will be:

$$F_{f} = 29\:N$$

Once again, the direction of $F_{f}$ will be opposite to the direction of the applied force.

**Answer:** At an applied force of 25 N, the object is stationary and the magnitude of the friction force is 25 N. At an applied force of 50 N, the object is in motion and the magnitude of the friction force is 29 N. In both cases, the force of friction is directed parallel to the surface and opposite to the direction of the applied force.

## Practice Problems
(Click **Cell** > **Run Cells** to generate new random values for each question. Refer to the previous table to get the coefficients of friction for specific materials.)

#import random
#import ipywidgets as widgets

#Randomize mass and friction coefficient
mass = random.randint(20,50)
coeff = (random.randint(10,100))/100

#Print question
question = "A " + str(mass) +" kg object is pushed across a flat horizontal surface. The coefficient of kinetic friction between the moving object and the surface is " + str(coeff) +". What is the magnitude of the friction force?"
print(question)

#Answer calculation
#Friction force = (friction coefficient) X (normal force)
answer = coeff*(mass*9.8)
answer = round(answer)

#Define range of values for random multiple choices
min = int(coeff*((mass-15)*9.8))
max = int(coeff*((mass+15)*9.8))

#Create three choices that are unique (and not equal to the answer)
choice_list = random.sample(range(min,max),3)
while choice_list.count(answer) >= 1:
    choice_list = random.sample(range(min,max),3)

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = str(answer) + " N"
option_2 = str(choice_list[0]) + " N"
option_3 = str(choice_list[1]) + " N"
option_4 = str(choice_list[2]) + " N"

multiple_choice(option_1, option_2, option_3, option_4)

#import random
#import ipywidgets as widgets

#Randomize mass and applied force
mass = random.randint(20,50)
applied_force = random.randint(150,300)

#Randomize material
material_options = ['steel', 'glass', 'wood']
material =random.choice(material_options)

#Define friction coefficients based on selected material
if material == 'steel':
    us = 0.7; uk = 0.6
elif material == 'glass':
    us = 0.9; uk = 0.4
elif material == 'wood':
    us = 0.4; uk = 0.2

#Print question
question = "If a %d kg %s object is pushed across a flat horizontal %s surface with an applied force of %d N, what is the magnitude of the friction force?" %(mass, material, material, applied_force)
print(question)

#Answer calculation
#Friction force = (friction coefficient) X (normal force)
static_friction = us*(mass*9.8)
kinetic_friction = uk*(mass*9.8)

#If the applied force is less than or equal to the maximum static friction force, the object will remain stationary
#The friction force equals the applied force
if applied_force <= static_friction:
    answer = applied_force
else:
    answer = kinetic_friction

answer = round(answer)

#Define range of values for random multiple choices
if applied_force <= static_friction:
    min = applied_force-15
    max = applied_force+15
else:
    min = int(uk*((mass-15)*9.8))
    max = int(uk*((mass+15)*9.8))

#Create three choices that are unique (and not equal to the answer)
choice_list = random.sample(range(min,max),3)
while choice_list.count(answer) >= 1:
    choice_list = random.sample(range(min,max),3)

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = str(answer) + " N"
option_2 = str(choice_list[0]) + " N"
option_3 = str(choice_list[1]) + " N"
option_4 = str(choice_list[2]) + " N"

multiple_choice(option_1, option_2, option_3, option_4)

#import random
#import ipywidgets as widgets

#Randomize applied and friction forces
applied_force = random.randint(51,75)
friction_force = random.randint(25,50)

#Randomize material
material_options = ['steel', 'glass', 'wood']
material =random.choice(material_options)

#Define friction coefficients based on selected material
if material == 'steel':
    uk = 0.6; us = 0.7
elif material == 'glass':
    uk = 0.4; us = 0.9
elif material == 'wood':
    uk = 0.2; us = 0.4

#Print question
question = "If a %s object is pushed across a flat horizontal %s surface with an applied force of %d N, and a friction force of %d N occurs, what is the magnitude of the normal force?" %(material, material, applied_force, friction_force)
print(question)

#Answer calculation
#weight = normal force = (friction force)/(kinetic friction coefficient)
answer = friction_force/uk
answer = round(answer)

#Define range of values for random multiple choices
min = int((friction_force-15)/uk); max = int((friction_force+15)/uk)

#Create three choices that are unique (and not equal to the answer)
choice_list = random.sample(range(min,max),3)
while choice_list.count(answer) >= 1:
    choice_list = random.sample(range(min,max),3)

#Assign each option to these four variables
#Option1 contains the answer
option_1 = str(answer) + " N"
option_2 = str(random.randint(min,max)) + " N"
option_3 = str(random.randint(min,max)) + " N"
option_4 = str(random.randint(min,max)) + " N"

multiple_choice(option_1, option_2, option_3, option_4)

#import random
#import ipywidgets as widgets
#import numpy as np

#Randomize mass and applied force
mass = random.randint(5,10)
applied_force = random.randint(46,80)
friction_force = random.randint(10,45)

#Print question
question = "A %d kg object is pulled across a flat horizontal surface by a force of %d N. The friction force is %d N. What is the coefficient of kinetic friction?" %(mass, applied_force, friction_force)
print(question)

#Answer calculation
#friction coefficient = (friction force) / (normal force)
answer = friction_force/(mass*9.8)
answer = round(answer,2)

#Define range of values for random multiple choices
min = 0.1
max = 0.9
unique = 0

#Create three choices that are unique (and not equal to the answer)
while unique < 4:
    choice_list = np.random.uniform(min, max, size=(3,))
    for i in range(3):
        choice_list[i] = round(choice_list[i],2)

    choice_list = np.append(choice_list, answer)
    list_unique = np.unique(choice_list)
    unique = list_unique.size

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = str(answer)
option_2 = str(choice_list[0])
option_3 = str(choice_list[1])
option_4 = str(choice_list[2])

multiple_choice(option_1, option_2, option_3, option_4)

Use the diagram below to answer the following question:

#import random
#import ipywidgets as widgets

#Randomize mass and friction coefficient
mass = random.randint(20,50)
coeff = (random.randint(10,100))/100

#Print question
question = "A " + str(mass) +" kg object is suspended by a pulley and connected to an object resting on a flat surface. The friction coefficient between the object and the surface is " + str(coeff) +". What is the minimum mass required to keep this suspended object stationary?"
print(question)

#Answer calculation
#Friction force = applied force = (mass) X (9.8)
friction_force = mass*9.8

normal_force = friction_force/coeff
answer = normal_force/9.8
answer = round(answer)

#Define range of values for random multiple choices
min = int((normal_force-50)/9.8)
max = int((normal_force+50)/9.8)

#Create three choices that are unique (and not equal to the answer)
choice_list = random.sample(range(min,max),3)
while choice_list.count(answer) >= 1:
    choice_list = random.sample(range(min,max),3)

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = str(answer) + " N"
option_2 = str(choice_list[0]) + " N"
option_3 = str(choice_list[1]) + " N"
option_4 = str(choice_list[2]) + " N"

multiple_choice(option_1, option_2, option_3, option_4)

## Experiment

As mentioned above, the coefficients of static and kinetic friction are determined experimentally for different materials.

**Determination of Static Friction**

Try the following experiment to determine the coefficient of static friction.

**Step 1:** Find an object and a flat horizontal surface. Record the material type for the object and surface.

**Step 2:** Measure the mass of the object using a mass balance (kg).

**Step 3:** Calculate the magnitude of the normal force using the following formula: $F_{n} = mg$

**Step 4:** Using a spring scale, gradually apply a force to the object. Record the value on the scale the moment the object begins to move. At this moment, the applied force is equal to the maximum static friction force.

**Step 5:** Calculate the coefficient of static friction using the following formula: $\mu_{s} = F_{f} \div F_{n}$

**Determination of Kinetic Friction**

Continue the experiment to determine the coefficient of kinetic friction.

**Step 6:** Using a spring scale, apply enough force to drag the object across the surface at a constant velocity (acceleration = 0). Record the value on the scale while the object is moving. So long as the object moves at a constant velocity, the applied force is equal to the kinetic friction force.

**Step 7:** Calculate the coefficient of kinetic friction using the following formula: $\mu_{k} = F_{f} \div F_{n}$

 (**Double click** this cell and update the table with your own data. Click **Cell** > **Run Cells** when done.)

Materials | Object mass (g) | Normal force (N) | Applied force (N) | Static friction coefficient | Kinetic friction coefficient
 ---      | ---             | ---              | ---               | ---                         | ----
 ?        | ?               | ?                | ?                 | ?                           | ?
 ?        | ?               | ?                | ?                 | ?                           | ?
 ?        | ?               | ?                | ?                 | ?                           | ?
 ?        | ?               | ?                | ?                 | ?                           | ?
 ?        | ?               | ?                | ?                 | ?                           | ?

## Force Diagrams

A useful way to visualize the friction forces is to construct a force diagram, as shown below. This diagram depicts the magnitudes of the forces acting on an object as it is pushed across a flat horizontal surface with increasing force. The y-axis depicts the friction force ($F_{f}$), and the x-axis depicts the applied force ($F_{a}$). The sliders can be manipulated to change the normal force ($F_{n}$), the coefficient of static friction ($\mu_{s}$), and the coefficient of kinetic friction ($\mu_{k}$).

#import ipywidgets as widgets
#import matplotlib.pyplot as plt

def f(Fn=50,μs=0.75,μk=0.25):
    #Fn = normal force
    #μs = coefficient of static friction
    #μk = coefficient of kinetic friction

    plt.figure()
    xs = Fn*μs
    xk = Fn*μk
    plt.plot([0,xs,xs,100],[0,xs,xk,xk])
    plt.plot([xs,xs],[xk,0], linestyle="dotted")
    plt.ylim(0, 100)
    plt.xlim(0,100)
    plt.ylabel('Friction force (N)')
    plt.xlabel('Applied force (N)')
    plt.annotate(xy=[xs-15,xs+5],s="Static friction (max)")
    plt.annotate(xy=[(xs+(100-xs)/2)-10,xk+5],s="Kinetic friction")
    plt.show()

interactive_plot = widgets.interactive(f,Fn=(35,75,5),μs=(0.5, 1.0),μk=(0.1, 0.5))
output = interactive_plot.children[-1]
output.layout.height = '280px'
interactive_plot

**Interpreting the graph**

Read the graph from left to right. As the applied force gradually increases along the x-axis, the friction force also increases. Notice that the magnitude of the friction force is equal to the applied force ($F_{f} = F_{a}$) until it reaches the point of maximum static friction. This point is shown on the graph as a **peak**. The point of maximum static friction is determined by the following equation: $F_{f}=\mu_{s} F_{n}$. As the applied force continues to increase beyond the peak of maximum static friction, the object begins to move. The friction force is now described by the kinetic friction equation: $F_{f}=\mu_{k} F_{n}$.

Move the slider for the normal force back and forth. As the normal force increases, what happens to the static and kinetic friction forces?

#import ipywidgets as widgets

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = "The static and kinetic friction forces both increase."
option_2 = "The static and kinetic friction forces both decrease."
option_3 = "The static friction force increases and the kinetic friction force decreases."
option_4 = "The static friction force decreases and the kinetic friction force increases."

multiple_choice(option_1, option_2, option_3, option_4)

Move the slider for the static friction coefficient back and forth. As the static friction coefficient increases, what happens to the static and kinetic friction forces?

#import ipywidgets as widgets

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = "The static friction force increases and the kinetic friction force remains constant."
option_2 = "The static friction force decreases and the kinetic friction force remains constant."
option_3 = "The static friction force increases and the kinetic friction force decreases."
option_4 = "The static friction force decreases and the kinetic friction force increases."

multiple_choice(option_1, option_2, option_3, option_4)

Move the slider for the kinetic friction coefficient back and forth. As the kinetic friction coefficient increases, what happens to the static and kinetic friction forces?

#import ipywidgets as widgets

#Assign each multiple choice to these four variables
#Option_1 contains the answer
option_1 = "The kinetic friction force increases and the static friction force remains constant."
option_2 = "The kinetic friction force decreases and the static friction force remains constant."
option_3 = "The kinetic friction force increases and the static friction force decreases."
option_4 = "The kinetic friction force decreases and the static friction force increases."

multiple_choice(option_1, option_2, option_3, option_4)

## Conclusions

In this notebook, the concepts of static and kinetic friction were examined. In summary:

* **Friction** describes the force that resists the relative motion of an object as it slides across a surface. Friction forces are proportional to the normal force:

$$F_{f} = \mu F_{n}$$

* **Static friction** describes the friction force that acts between an object and the surface to prevent it from sliding. Static friction must be overcome for an object to move.

* **Kinetic friction** describes the friction force that acts between an object and the surface it slides upon. Kinetic friction is used when describing objects in motion.

* **Coefficients of static and kinetic friction** are determined experimentally for different materials. Once determined, these values can be tabulated and used to solve friction problems. An experimental method for determining the coefficients of static and kinetic friction was presented.

* **Friction problems** can be solved using free-body diagrams, the friction formula, and the tabulated values for the coefficients of friction.

* **Force diagrams** can be used to visualize the relationship between the friction force, the applied force, the normal force, and the coefficients of static and kinetic friction.

Images in this notebook represent original artwork.

%%html

<form action="javascript:code_toggle()"><input type="submit" id="toggleButton" value="Show Code"></form>

[![Callysto.ca License](https://github.com/callysto/curriculum-notebooks/blob/master/callysto-notebook-banner-bottom.jpg?raw=true)](https://github.com/callysto/curriculum-notebooks/blob/master/LICENSE.md)


#!/usr/bin/env python3

import unittest
from unittest.mock import patch, MagicMock
import pandas as pd
import numpy as np

from tmc import points

from tmc.utils import load, get_out, patch_helper

module_name="src.bicycle_timeseries"
bicycle_timeseries = load(module_name, "bicycle_timeseries")
main = load(module_name, "main")
ph = patch_helper(module_name)

@points('p05-08.1')
class BicycleTimeseries(unittest.TestCase):

    # @classmethod
    # def setUpClass(cls):
    #     cls.df = bicycle_timeseries()

    def setUp(self):
        self.df = bicycle_timeseries()

    def test_shape(self):
        self.assertEqual(self.df.shape, (37128, 20), msg="Incorrect shape!")

    def test_columns(self):
        cols = ['Auroransilta', 'Eteläesplanadi', 'Huopalahti (asema)',
                'Kaisaniemi/Eläintarhanlahti', 'Kaivokatu', 'Kulosaaren silta et.',
                'Kulosaaren silta po. ', 'Kuusisaarentie', 'Käpylä, Pohjoisbaana',
                'Lauttasaaren silta eteläpuoli', 'Merikannontie',
                'Munkkiniemen silta eteläpuoli', 'Munkkiniemi silta pohjoispuoli',
                'Heperian puisto/Ooppera', 'Pitkäsilta itäpuoli',
                'Pitkäsilta länsipuoli', 'Lauttasaaren silta pohjoispuoli',
                'Ratapihantie', 'Viikintie', 'Baana']
        np.testing.assert_array_equal(self.df.columns, cols, err_msg="Incorrect columns!")

    def test_index(self):
        self.assertIsInstance(self.df.index[0], pd.Timestamp,
                              msg="Expected index to have type timestamp!")
        self.assertEqual(self.df.index[0], pd.to_datetime("2014-1-1 00:00"),
                         msg="Incorrect first index!")

        self.assertEqual(self.df.index[1], pd.to_datetime("2014-1-1 01:00"),
                         msg="Incorrect second index!")

    def test_calls(self):
        with patch(ph("bicycle_timeseries"), wraps=bicycle_timeseries) as pbts,\
             patch(ph("pd.read_csv"), wraps=pd.read_csv) as prc,\
             patch(ph("pd.to_datetime"), wraps=pd.to_datetime) as pdatetime:
            main()
            pbts.assert_called_once()
            prc.assert_called_once()
            pdatetime.assert_called()

if __name__ == '__main__':
    unittest.main()


# AUTOGENERATED! DO NOT EDIT! File to edit: 00_core.ipynb (unless otherwise specified).

__all__ = ['Matrix']

# Cell
import numpy

class Matrix():
    """
    Class generates a zero matrix
    """
    def __init__(self, n_matrix:int, m_matrix:int):
        self.n = n_matrix
        self.m = m_matrix
    def make_matrix(self):
        return numpy.zeros(self.n * self.m).reshape(self.n, self.m)


import numpy as np
arr = np.array([1,2,3,4,5,6,7,8])
print("Enumerating the array :-")
for index,x in np.ndenumerate(arr):
    print(index,x)


import numpy as np

class EarlyStopping:
    def __init__(self, patience=5):
        self.patience = patience
        self.counter = 0
        self.best_loss = np.Inf

    def __call__(self, val_loss):
        """
        if you use other metrics where a higher value is better, e.g. accuracy,
        call this with its corresponding negative value
        """
        if val_loss < self.best_loss:
            early_stop = False
            get_better = True
            self.counter = 0
            self.best_loss = val_loss
        else:
            get_better = False
            self.counter += 1
            if self.counter >= self.patience:
                early_stop = True
            else:
                early_stop = False

        return early_stop, get_better


import numpy as np
from termcolor import colored
import os
import sys
if sys.platform == 'linux':
    sys.path.append(r'../lib')
else:
    sys.path.append(os.path.abspath('../build/x64/Release'))
import NumCpp

####################################################################################
def doTest():
    print(colored('Testing Utils', 'magenta'))
    print(colored('Testing num2str', 'cyan'))
    value = np.random.randint(1, 100, [1, ], dtype=np.int8).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS int8', 'green'))
    else:
        print(colored('\tFAIL int8', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int16).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS int16', 'green'))
    else:
        print(colored('\tFAIL int16', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int32).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS int32', 'green'))
    else:
        print(colored('\tFAIL int32', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int64).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS int64', 'green'))
    else:
        print(colored('\tFAIL int64', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint8).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS uint8', 'green'))
    else:
        print(colored('\tFAIL uint8', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint16).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS uint16', 'green'))
    else:
        print(colored('\tFAIL uint16', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint32).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS uint32', 'green'))
    else:
        print(colored('\tFAIL uint32', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint64).item()
    if NumCpp.num2str(value) == str(value):
        print(colored('\tPASS uint64', 'green'))
    else:
        print(colored('\tFAIL uint64', 'red'))

    print(colored('Testing sqr', 'cyan'))
    value = np.random.randint(1, 12, [1, ], dtype=np.int8).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS int8', 'green'))
    else:
        print(colored('\tFAIL int8', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int16).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS int16', 'green'))
    else:
        print(colored('\tFAIL int16', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int32).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS int32', 'green'))
    else:
        print(colored('\tFAIL int32', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int64).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS int64', 'green'))
    else:
        print(colored('\tFAIL int64', 'red'))

    value = np.random.randint(1, 15, [1, ], dtype=np.uint8).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS uint8', 'green'))
    else:
        print(colored('\tFAIL uint8', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint16).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS uint16', 'green'))
    else:
        print(colored('\tFAIL uint16', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint32).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS uint32', 'green'))
    else:
        print(colored('\tFAIL uint32', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint64).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS uint64', 'green'))
    else:
        print(colored('\tFAIL uint64', 'red'))

    value = np.random.randint(1, 100, [1, ]).astype(np.double).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS double', 'green'))
    else:
        print(colored('\tFAIL double', 'red'))

    value = np.random.randint(1, 100, [1, ]).astype(np.float32).item()
    if NumCpp.sqr(value) == value ** 2:
        print(colored('\tPASS float', 'green'))
    else:
        print(colored('\tFAIL float', 'red'))

    print(colored('Testing cube', 'cyan'))
    value = np.random.randint(1, 6, [1, ], dtype=np.int8).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS int8', 'green'))
    else:
        print(colored('\tFAIL int8', 'red'))

    value = np.random.randint(1, 32, [1, ], dtype=np.int16).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS int16', 'green'))
    else:
        print(colored('\tFAIL int16', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int32).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS int32', 'green'))
    else:
        print(colored('\tFAIL int32', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.int64).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS int64', 'green'))
    else:
        print(colored('\tFAIL int64', 'red'))

    value = np.random.randint(1, 7, [1, ], dtype=np.uint8).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS uint8', 'green'))
    else:
        print(colored('\tFAIL uint8', 'red'))

    value = np.random.randint(1, 41, [1, ], dtype=np.uint16).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS uint16', 'green'))
    else:
        print(colored('\tFAIL uint16', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint32).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS uint32', 'green'))
    else:
        print(colored('\tFAIL uint32', 'red'))

    value = np.random.randint(1, 100, [1, ], dtype=np.uint64).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS uint64', 'green'))
    else:
        print(colored('\tFAIL uint64', 'red'))

    value = np.random.randint(1, 100, [1, ]).astype(np.double).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS double', 'green'))
    else:
        print(colored('\tFAIL double', 'red'))

    value = np.random.randint(1, 100, [1, ]).astype(np.float32).item()
    if NumCpp.cube(value) == value ** 3:
        print(colored('\tPASS float', 'green'))
    else:
        print(colored('\tFAIL float', 'red'))

    print(colored('Testing power', 'cyan'))
    value = np.random.randint(1, 4, [1, ], dtype=np.int8).item()
    power = np.random.randint(1, 4, dtype=np.uint8).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS int8', 'green'))
    else:
        print(colored('\tFAIL int8', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.int16).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS int16', 'green'))
    else:
        print(colored('\tFAIL int16', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.int32).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS int32', 'green'))
    else:
        print(colored('\tFAIL int32', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.int64).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS int64', 'green'))
    else:
        print(colored('\tFAIL int64', 'red'))

    value = np.random.randint(1, 4, [1, ], dtype=np.uint8).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS uint8', 'green'))
    else:
        print(colored('\tFAIL uint8', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.uint16).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS uint16', 'green'))
    else:
        print(colored('\tFAIL uint16', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.uint32).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS uint32', 'green'))
    else:
        print(colored('\tFAIL uint32', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.uint64).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS uint64', 'green'))
    else:
        print(colored('\tFAIL uint64', 'red'))

    value = np.random.randint(1, 10, [1, ]).astype(np.double).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS double', 'green'))
    else:
        print(colored('\tFAIL double', 'red'))

    value = np.random.randint(1, 10, [1, ]).astype(np.float32).item()
    if NumCpp.power(value, power) == value ** power:
        print(colored('\tPASS float', 'green'))
    else:
        print(colored('\tFAIL float', 'red'))

    print(colored('Testing powerf', 'cyan'))
    value = np.random.randint(1, 4, [1, ], dtype=np.int8).item()
    power = np.random.rand(1).item() * 10
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS int8', 'green'))
    else:
        print(colored('\tFAIL int8', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.int16).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS int16', 'green'))
    else:
        print(colored('\tFAIL int16', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.int32).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS int32', 'green'))
    else:
        print(colored('\tFAIL int32', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.int64).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS int64', 'green'))
    else:
        print(colored('\tFAIL int64', 'red'))

    value = np.random.randint(1, 4, [1, ], dtype=np.uint8).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS uint8', 'green'))
    else:
        print(colored('\tFAIL uint8', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.uint16).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS uint16', 'green'))
    else:
        print(colored('\tFAIL uint16', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.uint32).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS uint32', 'green'))
    else:
        print(colored('\tFAIL uint32', 'red'))

    value = np.random.randint(1, 10, [1, ], dtype=np.uint64).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS uint64', 'green'))
    else:
        print(colored('\tFAIL uint64', 'red'))

    value = np.random.randint(1, 10, [1, ]).astype(np.double).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS double', 'green'))
    else:
        print(colored('\tFAIL double', 'red'))

    value = np.random.randint(1, 10, [1, ]).astype(np.float32).item()
    if NumCpp.powerf(value, power) == value ** power:
        print(colored('\tPASS float', 'green'))
    else:
        print(colored('\tFAIL float', 'red'))

####################################################################################
if __name__ == '__main__':
    doTest()


import theano
import numpy as np

# You can get the values being used to configure Theano like so:
print(theano.config.device)
print(theano.config.floatX)

# You can also get/set them at runtime:
old_floatX = theano.config.floatX
theano.config.floatX = 'float32'

# Be careful that you're actually using floatX!
# For example, the following will cause var to be a float64 regardless of floatX due to numpy defaults:
var = theano.shared(np.array([1.3, 2.4]))
print(var.type()) #!!!
# So, whenever you use a numpy array, make sure to set its dtype to theano.config.floatX
var = theano.shared(np.array([1.3, 2.4], dtype=theano.config.floatX))
print(var.type())
# Revert to old value
theano.config.floatX = old_floatX


""" Tests whether the results of the problems are correct. That way, we can safely change
shared functions without breaking past solutions.

Recommended usage: run `pytest -v` while inside the repository. Because it may take up to a minute
per solved problem, use sparingly.

WARNING: don't read this file if you don't want to see the solutions to the problems. There
is no joy in that, am I right? ;)
"""

import os
import time
from datetime import timedelta
import importlib
import pytest

from jax.config import config
config.update("jax_enable_x64", True)   # Critical to test 64-bit dependent problems (e.g. prob. 3)

SOLUTIONS_DIR = os.path.join(
    os.path.dirname(os.path.abspath(__file__)),
    '..',
    'gante_project_euler',
    'solutions'
)
SOLUTIONS = {
    1: 233168,
    2: 4613732,
    3: 6857,
    4: 906609,
    5: 232792560,
    6: 25164150,
    7: 104743,
    9: 31875000,
    10: 142913828922,
    12: 76576500,
}

def test_coverage():
    """ Tests whether all problems have a solution here. At most 1 problem may be missing its
    solution (the problem that is being worked on at the moment).
    """
    num_solutions = len(SOLUTIONS)
    num_problems = len(
        [f for f in os.listdir(SOLUTIONS_DIR) if os.path.isfile(os.path.join(SOLUTIONS_DIR, f))]
    )
    assert num_problems - num_solutions <= 1, \
        "Missing solutions! ({} problems, {} solutions)".format(num_problems, num_solutions)

@pytest.mark.parametrize("problem_idx", list(SOLUTIONS.keys()))
def test_results(problem_idx):
    """ Tests whether the solutions of the problems are correct and that they run within a minute.
    """
    os.environ["CUDA_VISIBLE_DEVICES"] = "0"
    if problem_idx < 10:
        module_termination = "00" + str(problem_idx)
    elif problem_idx < 100:
        module_termination = "0" + str(problem_idx)
    else:
        module_termination = str(problem_idx)
    module_name = "gante_project_euler.solutions.problem_" + module_termination
    module = importlib.import_module(module_name)
    start = time.time()
    result = module.get_solution()
    end = time.time()
    assert result == SOLUTIONS[problem_idx], \
        "The result ({}) did not match the solution ({})!".format(result, SOLUTIONS[problem_idx])
    duration = timedelta(seconds=end-start)
    assert duration < timedelta(minutes=1), \
        "It took more than a minute to run! (duration = {})".format(duration)


import pandas as pd
import numpy as np
import csv
from sklearn.utils import shuffle

def main():
    arr = np.arange(0, 100)
    df = pd.DataFrame(arr, columns=["berat"])
    df.to_csv("./deneme.csv", index=False, encoding="utf-8")

    df = pd.read_csv("./deneme.csv")

    df = shuffle(df)
    df.to_csv("./shuffle_deneme.csv", index=False, encoding="utf-8")

main()