# A brief tour of the IPython notebook

This document will give you a brief tour of the capabilities of the IPython notebook.
You can view its contents by scrolling around, or execute each cell by typing `Shift-Enter`.

The rest of the notebooks in this directory illustrate various other aspects and
capabilities of the IPython notebook; some of them may require additional libraries to be executed.

**NOTE:** This notebook *must* be run from its own directory, so you must ``cd``
to this directory and then start the notebook, but do *not* use the ``--notebook-dir``
option to run it from another location.

The first thing you need to know is that you are still controlling the same old IPython you're used to,
so things like shell aliases and magic commands still work:

```
pwd
```

    u'/home/fperez/ipython/tutorial/notebooks'

```
ls
```

    animation.m4v                        P10 Basic Interface.ipynb
    argv.py                              P15 Parallel Magics.ipynb
    cat.py*                              P20 Multiplexing.ipynb
    Cell Magics.ipynb                    P21 LoadBalancing.ipynb
    Display control.ipynb                P30 Working with MPI.ipynb
    figs/                                P99 Summary.ipynb
    foo.py                               PX01 Example - Remote Iteration.ipynb
    lnum.py*                             python-logo.svg
    myscript.py                          PZ Performance.ipynb
    nb@                                  soln/
    nbtour.ipynb                         text_analysis.py*
    P01 Overview and Architecture.ipynb

```
message = 'The IPython notebook is great!'
# note: the echo command does not run on Windows, it's a unix command.
!echo $message
```

    The IPython notebook is great!

## Plots with matplotlib

IPython adds an 'inline' matplotlib backend,
which embeds any matplotlib figures into the notebook.

```
%pylab inline
```

    Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].
    For more information, type 'help(pylab)'.

```
x = linspace(0, 3*pi, 500)
plot(x, sin(x**2))
title('A simple chirp');
```

You can paste blocks of input with prompt markers, such as those from
[the official Python tutorial](http://docs.python.org/tutorial/interpreter.html#interactive-mode)

```
>>> the_world_is_flat = 1
>>> if the_world_is_flat:
...     print "Be careful not to fall off!"
```

    Be careful not to fall off!

Errors are shown in informative ways:

```
%run non_existent_file
```

    ERROR: File `u'non_existent_file.py'` not found.

```
x = 1
y = 4
z = y/(1-x)
```

When IPython needs to display additional information (such as providing details on an object via `x?`
it will automatically invoke a pager at the bottom of the screen:

```
magic
```

## Non-blocking output of kernel

If you execute the next cell, you will see the output arriving as it is generated, not all at the end.

```
import time, sys
for i in range(8):
    print i,
    time.sleep(0.5)
```

    0 1 2 3 4 5 6 7

## Clean crash and restart

We call the low-level system libc.time routine with the wrong argument via
ctypes to segfault the Python interpreter:

```
import sys
from ctypes import CDLL
# This will crash a Linux or Mac system; equivalent calls can be made on Windows
dll = 'dylib' if sys.platform == 'darwin' else 'so.6'
libc = CDLL("libc.%s" % dll)
libc.time(-1)  # BOOM!!
```

## Markdown cells can contain formatted text and code

You can *italicize*, **boldface**

* build
* lists

and embed code meant for illustration instead of execution in Python:

    def f(x):
        """a docstring"""
        return x**2

or other languages:

    if (i=0; i<n; i++) {
      printf("hello %d\n", i);
      x += 4;
    }

Courtesy of MathJax, you can include mathematical expressions both inline:
$e^{i\pi} + 1 = 0$  and displayed:

$$e^x=\sum_{i=0}^\infty \frac{1}{i!}x^i$$

## Rich displays: include anyting a browser can show

Note that we have an actual protocol for this, see the `display_protocol` notebook for further details.

### Images

```
from IPython.display import Image
Image(filename='figs/logo.png')
```

An image can also be displayed from raw data or a url

```
Image(url='http://python.org/images/python-logo.gif')
```

SVG images are also supported out of the box (since modern browsers do a good job of rendering them):

```
from IPython.display import SVG
SVG(filename='figs/python-logo.svg')
```

### Video

And more exotic objects can also be displayed, as long as their representation supports
the IPython display protocol.

For example, videos hosted externally on YouTube are easy to load (and writing a similar wrapper for other
hosted content is trivial):

```
from IPython.display import YouTubeVideo
# a talk about IPython at Sage Days at U. Washington, Seattle.
# Video credit: William Stein.
YouTubeVideo('1j_HxD4iLn8')
```

Using the nascent video capabilities of modern browsers, you may also be able to display local
videos.  At the moment this doesn't work very well in all browsers, so it may or may not work for you;
we will continue testing this and looking for ways to make it more robust.

The following cell loads a local file called  `animation.m4v`, encodes the raw video as base64 for http
transport, and uses the HTML5 video tag to load it. On Chrome 15 it works correctly, displaying a control
bar at the bottom with a play/pause button and a location slider.

```
from IPython.display import HTML
video = open("figs/animation.m4v", "rb").read()
video_encoded = video.encode("base64")
video_tag = '<video controls alt="test" src="data:video/x-m4v;base64,{0}">'.format(video_encoded)
HTML(data=video_tag)
```

<video controls alt="test" src="data:video/x-m4v;base64,AAAAHGZ0eXBNNFYgAAACAGlzb21pc28yYXZjMQAAAAhmcmVlAAAqiW1kYXQAAAKMBgX//4jcRem9
5tlIt5Ys2CDZI+7veDI2NCAtIGNvcmUgMTE4IC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENv
cHlsZWZ0IDIwMDMtMjAxMSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9w
dGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1o
ZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2
IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0
X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBu
cj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9p
bnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEg
d2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNSBz
Y2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9
MSBjcmY9MjMuMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89
MS40MCBhcT0xOjEuMDAAgAAACqVliIQAV/0TAAI/3gU2tIW7KawwaCmQGTGHKmuYAAADACBcshU+
yICkgAA14AHowiEeT6ei7v7h3Hu0i2fpUBLGBIkbCMP3Vfz+9BVGCDXnw9Uv5o3iN030tb7eq6rs
EEhHs2azbdTiE9Csz5Zm6SiUWRdmB43hbD5i6syATuODUJd7LM3d9cbFpc7zFlu5y3vUmNGd6urp
vKKT9iyleIyTuR1sVS431DhevGfkUllVeIznYUe2USoMW1tufETjyRdmGldN6eNlhAOsGAH4z+Hk
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
">

## Local Files

The above examples embed images and video from the notebook filesystem in the output
areas of code cells.  It is also possible to request these files directly in markdown cells
if they reside in the notebook directory via relative urls prefixed with `files/`:

    files/[subdirectory/]<filename>

For example, in the example notebook folder, we have the Python logo, addressed as:

and a video with the HTML5 video tag:

    <video controls src="files/figs/animation.m4v" />

<video controls src="/files/figs/animation.m4v" />

These do not embed the data into the notebook file,
and require that the files exist when you are viewing the notebook.

### Security of local files

Note that this means that the IPython notebook server also acts as a generic file server
for files inside the same tree as your notebooks.  Access is not granted outside the
notebook folder so you have strict control over what files are visible, but for this
reason it is highly recommended that you do not run the notebook server with a notebook
directory at a high level in your filesystem (e.g. your home directory).

When you run the notebook in a password-protected manner, local file access is restricted
to authenticated users unless read-only views are active.

### External sites

You can even embed an entire page from another site in an iframe; for example this is today's Wikipedia
page for mobile users:

```
HTML('<iframe src=http://en.mobile.wikipedia.org/?useformat=mobile width=700 height=350>')
```

<iframe src=http://en.mobile.wikipedia.org/?useformat=mobile width=700 height=350>

# Loading external codes
* Drag and drop a ``.py`` in the dashboard
* Use ``%load`` with any local or remote url: [the Matplotlib Gallery!](http://matplotlib.sourceforge.net/gallery.html)

In this notebook we've kept the output saved so you can see the result, but you should run the next
cell yourself (with an active internet connection).

Let's make sure we have pylab again, in case we have restarted the kernel due to the crash demo above

```
%pylab inline
```

    Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].
    For more information, type 'help(pylab)'.

```
%load http://matplotlib.sourceforge.net/mpl_examples/pylab_examples/integral_demo.py
```

## Mathematics and SymPy support

And we also support the display of mathematical expressions typeset in LaTeX, which is rendered
in the browser thanks to the [MathJax library](http://mathjax.org).

Note that this is *different* from the above examples.  Above we were typing mathematical expressions
in Markdown cells (along with normal text) and letting the browser render them; now we are displaying
the output of a Python computation as a LaTeX expression wrapped by the `Math()` object so the browser
renders it.  The `Math` object will add the needed LaTeX delimiters (`$$`) if they are not provided:

```
from IPython.display import Math
Math(r'F(k) = \int_{-\infty}^{\infty} f(x) e^{2\pi i k} dx')
```

$$F(k) = \int_{-\infty}^{\infty} f(x) e^{2\pi i k} dx$$

With the `Latex` class, you have to include the delimiters yourself.  This allows you to use other LaTeX modes such as `eqnarray`:

```
from IPython.display import Latex
Latex(r"""\begin{eqnarray}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{eqnarray}""")
```

\begin{eqnarray}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{eqnarray}

Using these tools, we can integrate with the [SymPy](http://sympy.org) package to perform symbolic manipulations,
and combined with numpy and matplotlib, also displays numerical visualizations of symbolically
constructed expressions.

We first load sympy printing and plotting support, as well as all of sympy:

```
%load_ext sympyprinting
%pylab inline

from __future__ import division
import sympy as sym
from sympy import *
x, y, z = symbols("x y z")
k, m, n = symbols("k m n", integer=True)
f, g, h = map(Function, 'fgh')
```

    Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].
    For more information, type 'help(pylab)'.

<h2>Elementary operations</h2>

```
Rational(3,2)*pi + exp(I*x) / (x**2 + y)
```

```
exp(I*x).subs(x,pi).evalf()
```

```
exp(pi * sqrt(163)).evalf(50)
```

<h2>Algebra<h2>

```
eq = ((x+y)**2 * (x+1))
eq
```

```
expand(eq)
```

```
a = 1/x + (x*sin(x) - 1)/x
a
```

```
simplify(a)
```

<h2>Calculus</h2>

```
limit((sin(x)-x)/x**3, x, 0)
```

```
(1/cos(x)).series(x, 0, 6)
```

```
diff(cos(x**2)**2 / (1+x), x)
```

```
integrate(x**2 * cos(x), (x, 0, pi/2))
```

```
eqn = Eq(Derivative(f(x),x,x) + 9*f(x), 1)
display(eqn)
dsolve(eqn, f(x))
```

# Illustrating Taylor series

We will define a function to compute the Taylor series expansions of a symbolically defined expression at
various orders and visualize all the approximations together with the original function

```
def plot_taylor_approximations(func, x0=None, orders=(2, 4), xrange=(0,1), yrange=None, npts=200):
    """Plot the Taylor series approximations to a function at various orders.

    Parameters
    ----------
    func : a sympy function
    x0 : float
      Origin of the Taylor series expansion.  If not given, x0=xrange[0].
    orders : list
      List of integers with the orders of Taylor series to show.  Default is (2, 4).
    xrange : 2-tuple or array.
      Either an (xmin, xmax) tuple indicating the x range for the plot (default is (0, 1)),
      or the actual array of values to use.
    yrange : 2-tuple
      (ymin, ymax) tuple indicating the y range for the plot.  If not given,
      the full range of values will be automatically used.
    npts : int
      Number of points to sample the x range with.  Default is 200.
    """
    if not callable(func):
        raise ValueError('func must be callable')
    if isinstance(xrange, (list, tuple)):
        x = np.linspace(float(xrange[0]), float(xrange[1]), npts)
    else:
        x = xrange
    if x0 is None: x0 = x[0]
    xs = sym.Symbol('x')
    # Make a numpy-callable form of the original function for plotting
    fx = func(xs)
    f = sym.lambdify(xs, fx, modules=['numpy'])
    # We could use latex(fx) instead of str(), but matploblib gets confused
    # with some of the (valid) latex constructs sympy emits.  So we play it safe.
    plot(x, f(x), label=str(fx), lw=2)
    # Build the Taylor approximations, plotting as we go
    apps = {}
    for order in orders:
        app = fx.series(xs, x0, n=order).removeO()
        apps[order] = app
        # Must be careful here: if the approximation is a constant, we can't
        # blindly use lambdify as it won't do the right thing.  In that case,
        # evaluate the number as a float and fill the y array with that value.
        if isinstance(app, sym.numbers.Number):
            y = np.zeros_like(x)
            y.fill(app.evalf())
        else:
            fa = sym.lambdify(xs, app, modules=['numpy'])
            y = fa(x)
        tex = sym.latex(app).replace('$', '')
        plot(x, y, label=r'$n=%s:\, %s$' % (order, tex) )

    # Plot refinements
    if yrange is not None:
        plt.ylim(*yrange)
    grid()
    legend(loc='best').get_frame().set_alpha(0.8)
```

With this function defined, we can now use it for any sympy function or expression

```
plot_taylor_approximations(sin, 0, [2, 4, 6], (0, 2*pi), (-2,2))
```

```
plot_taylor_approximations(cos, 0, [2, 4, 6], (0, 2*pi), (-2,2))
```

### Exercise: illustrate the convergence radius of a Taylor series expansion

Remember that a Taylor series is useless beyond its convergence radius, as can be nicely illustrated by
a simple function that has singularities on the real axis.  Use the `plot_taylor_approximations` function to show how badly various orders (say $n= 2, 4, 6$) converge for $f(x) = \frac{1}{\cos(x)}$.

```

```

notebooks/Z0. A quick tour of the IPython notebook.ipynb


```python
# Erasmus+ ICCT project (2018-1-SI01-KA203-047081)

# Toggle cell visibility

from IPython.display import HTML
tag = HTML('''
Promijeni vidljivost <a href="javascript:code_toggle()">ovdje</a>.''')
display(tag)

# Hide the code completely

# from IPython.display import HTML
# tag = HTML('''<style>
# div.input {
#     display:none;
# }
# </style>''')
# display(tag)

```

Promijeni vidljivost ovdje.

## Unutaranja stabilnost - primjer 3

### Kako koristiti ovaj interaktivni primjer?

Pokušajte promijeniti matricu dinamike $A$ stabilnog linearnog sustava (prikazanog ispod) kako biste dobili sustav s konvergentnim i divergentnim modovima, a zatim promijenite početne uvjete kako biste sakrili divergentni mod.

$$
\dot{x} = \underbrace{\begin{bmatrix}0&1\\-1&-2\end{bmatrix}}_{A}x
$$

Pokušajte odgovoriti:
- Kako se može podesiti prikladno početno stanje?

```python
%matplotlib inline
import control as control
import numpy
import sympy as sym
from IPython.display import display, Markdown
import ipywidgets as widgets
import matplotlib.pyplot as plt

#matrixWidget is a matrix looking widget built with a VBox of HBox(es) that returns a numPy array as value !
class matrixWidget(widgets.VBox):
    def updateM(self,change):
        for irow in range(0,self.n):
            for icol in range(0,self.m):
                self.M_[irow,icol] = self.children[irow].children[icol].value
                #print(self.M_[irow,icol])
        self.value = self.M_

    def dummychangecallback(self,change):
        pass

    def __init__(self,n,m):
        self.n = n
        self.m = m
        self.M_ = numpy.matrix(numpy.zeros((self.n,self.m)))
        self.value = self.M_
        widgets.VBox.__init__(self,
                             children = [
                                 widgets.HBox(children =
                                              [widgets.FloatText(value=0.0, layout=widgets.Layout(width='90px')) for i in range(m)]
                                             )
                                 for j in range(n)
                             ])

        #fill in widgets and tell interact to call updateM each time a children changes value
        for irow in range(0,self.n):
            for icol in range(0,self.m):
                self.children[irow].children[icol].value = self.M_[irow,icol]
                self.children[irow].children[icol].observe(self.updateM, names='value')
        #value = Unicode('example@example.com', help="The email value.").tag(sync=True)
        self.observe(self.updateM, names='value', type= 'All')

    def setM(self, newM):
        #disable callbacks, change values, and reenable
        self.unobserve(self.updateM, names='value', type= 'All')
        for irow in range(0,self.n):
            for icol in range(0,self.m):
                self.children[irow].children[icol].unobserve(self.updateM, names='value')
        self.M_ = newM
        self.value = self.M_
        for irow in range(0,self.n):
            for icol in range(0,self.m):
                self.children[irow].children[icol].value = self.M_[irow,icol]
        for irow in range(0,self.n):
            for icol in range(0,self.m):
                self.children[irow].children[icol].observe(self.updateM, names='value')
        self.observe(self.updateM, names='value', type= 'All')

                #self.children[irow].children[icol].observe(self.updateM, names='value')

#overlaod class for state space systems that DO NOT remove "useless" states (what "professor" of automatic control would do this?)
class sss(control.StateSpace):
    def __init__(self,*args):
        #call base class init constructor
        control.StateSpace.__init__(self,*args)
    #disable function below in base class
    def _remove_useless_states(self):
        pass
```

```python
# Preparatory cell

A = numpy.matrix([[0.,1.],[-1.,-2.]])
X0 = numpy.matrix([[0.],[0.]])

Aw = matrixWidget(2,2)
Aw.setM(A)
X0w = matrixWidget(2,1)
X0w.setM(X0)
```

```python
# Misc

#create dummy widget
DW = widgets.FloatText(layout=widgets.Layout(width='0px', height='0px'))

#create button widget
START = widgets.Button(
    description='Test',
    disabled=False,
    button_style='', # 'success', 'info', 'warning', 'danger' or ''
    tooltip='Test',
    icon='check'
)

def on_start_button_clicked(b):
    #This is a workaround to have intreactive_output call the callback:
    #   force the value of the dummy widget to change
    if DW.value> 0 :
        DW.value = -1
    else:
        DW.value = 1
    pass
START.on_click(on_start_button_clicked)
```

```python
# Main cell

def main_callback(A, X0, DW):
    sols = numpy.linalg.eig(A)
    sys = sss(A,[[0],[1]],[1,0],0)
    pole = control.pole(sys)
    if numpy.real(pole[0]) != 0:
        p1r = abs(numpy.real(pole[0]))
    else:
        p1r = 1
    if numpy.real(pole[1]) != 0:
        p2r = abs(numpy.real(pole[1]))
    else:
        p2r = 1
    if numpy.imag(pole[0]) != 0:
        p1i = abs(numpy.imag(pole[0]))
    else:
        p1i = 1
    if numpy.imag(pole[1]) != 0:
        p2i = abs(numpy.imag(pole[1]))
    else:
        p2i = 1

    print('Svojstvene vrijednosti od A su:',round(sols[0][0],4),'i',round(sols[0][1],4))

    #T = numpy.linspace(0, 60, 1000)
    T, yout, xout = control.initial_response(sys,X0=X0,return_x=True)

    fig = plt.figure("Slobodni odziv", figsize=(16,5))
    ax = fig.add_subplot(121)
    plt.plot(T,xout[0])
    plt.grid()
    ax.set_xlabel('vrijeme [s]')
    ax.set_ylabel(r'$x_1$')

    ax1 = fig.add_subplot(122)
    plt.plot(T,xout[1])
    plt.grid()
    ax1.set_xlabel('vrijeme [s]')
    ax1.set_ylabel(r'$x_2$')

alltogether = widgets.HBox([widgets.VBox([widgets.Label('$A$:',border=3),
                                          Aw]),
                                          widgets.Label('   ',border=3),
                            widgets.VBox([widgets.Label('$X_0$:',border=3),
                                          X0w]),
                                          START])
out = widgets.interactive_output(main_callback, {'A':Aw, 'X0':X0w, 'DW':DW})
out.layout.height = '400px'
display(out, alltogether)
```

    Output(layout=Layout(height='400px'))

    HBox(children=(VBox(children=(Label(value='$A$:'), matrixWidget(children=(HBox(children=(FloatText(value=0.0, …

```python
#create dummy widget 2
DW2 = widgets.FloatText(layout=widgets.Layout(width='0px', height='0px'))
DW2.value = -1

#create button widget
START2 = widgets.Button(
    description='Prikaži odgovore',
    disabled=False,
    button_style='', # 'success', 'info', 'warning', 'danger' or ''
    tooltip='Klikni za prikaz odgovora',
    icon='check'
)

def on_start_button_clicked2(b):
    #This is a workaround to have intreactive_output call the callback:
    #   force the value of the dummy widget to change
    if DW2.value> 0 :
        DW2.value = -1
    else:
        DW2.value = 1
    pass
START2.on_click(on_start_button_clicked2)

def main_callback2(DW2):
    if DW2 > 0:
        display(Markdown(r'''>Odgovor: Početno stanje mora biti linearna kombinacija samo svojstvenih vektora pridruženih stabilnim polovima.
        $$ $$
        Primjer:
        $$
        A = \begin{bmatrix} 3 & 1 \\ 0 & -2 \end{bmatrix}, \quad x_0 = \begin{bmatrix} -\frac{1}{5} \\ 1 \end{bmatrix} \text{gdje je $x_0$ svojstveni vektor pridružen stabilnom polu $-2$ .}
        $$'''))
    else:
        display(Markdown(''))

#create a graphic structure to hold all widgets
alltogether2 =  widgets.VBox([START2])

out2 = widgets.interactive_output(main_callback2,{'DW2':DW2})
#out.layout.height = '300px'
display(out2,alltogether2)
```

    Output()

    VBox(children=(Button(description='Prikaži odgovore', icon='check', style=ButtonStyle(), tooltip='Klikni za pr…

```python

```


# Basics

In this notebook, we will cover the basics of OCaml programming langauge.

## Why OCaml

* OCaml is an industrial-strength, functional programming language.
    + In the same family as Haskell and Standard ML.
    + Initially developed at INRIA, and is now a healthy open-source project developed on [Github](https://github.com/ocaml/ocaml)
* Good mix of functional, imperative and object-oriented features.
* A fast compiler that produces efficient native code for x86, ARM, RISC-V, etc., as well as JavaScript.
* Users include
    + JaneStreet (almost everything from Hardware that injests market data to trading algorithms to infrastructure)
    + Microsoft (Everest project, F* programming language)
    + Facebook (Hack, Infer, Flow, ReasonML). [More than 50% messenger.com is ReasonML](https://reasonml.github.io/blog/2017/09/08/messenger-50-reason.html).
    + Docker (for Mac and Windows use MirageOS libraries).
    + and a variety of other research projects including Coq proof assistant, Compcert verified C compiler, MirageOS Unikernel OS, etc.

Ultimately, functional programming offers an alternative way to think about _programming_, which is useful even if you don't intend to use a functional programming language. That said, functional programming concepts such as  immutability, lambdas, coroutines, promises, monads, lenses, applicatives, functors, Hindley-Damas-Milner type inference are being adopted in mainstream imperative languages in C++, Java, Python, Rust etc., but also new languages that run on your favourite platform Clojure and Kotlin on the JVM, Elixir on Erlang OTP, etc.

## Jupyter notebook

We will be learning OCaml using Jupyter notebooks.

| Command           | Key Combo        |
|-------------------|------------------|
| Run cell          | ctrl + `<enter>` |
| Delete cell       | dd               |
| Insert cell above | a                |
| Insert cell below | b                |

## Variables

### Let binding

At its simplest, a variable is an identifier whose meaning is bound to a particular value. In OCaml these bindings are introduced using the let keyword.

```OCaml
let pi = 3
```

    val pi : int = 3

As you can see from the output pi is now bound to the value 3. Its type has also been inferred as int.

Every variable binding has a scope, which is the portion of the code that can refer to that binding. The scope of top-level let bindings -- like the one above -- is everything that follows it.

```OCaml
2 * pi * 5
```

    - : int = 30

### Primitive data types

OCaml offers the following primitive data types int, float, bool, char, string and unit.

```OCaml
let one = 1

let pi = 3.1415

let are_you_awesome = true

let a = 'a'

let hello = "Hello"

let unit = ()
```

    val one : int = 1

    val pi : float = 3.1415

    val are_you_awesome : bool = true

    val a : char = 'a'

    val hello : string = "Hello"

    val unit : unit = ()

Observe that the types are inferred. One of the key features of OCaml is type inference and type checking. For example, checking the equality of incompatible types fails with a compile time error.

```OCaml
one = pi
```

### Local let bindings

We can also use let to create a variable binding whose scope is limited to a particular expression using the in keyword:

```OCaml
let i =
  let j = 5 in
  j + 2
```

    val i : int = 7

As you can see from the output, only i has been bound to a value at the top-level. The j variable is no longer in scope:

```OCaml
j+4
```

## Conditionals

Unsurprisingly, OCaml provides conditional expressions using the if keyword:

```OCaml
let a = if i < 10 then i else 10
```

    val a : int = 7

## Functions

### Function definition

The let keyword can also be used to define functions:

```OCaml
let succ x = x + 1
```

    val succ : int -> int = <fun>

This defines a function called succ which takes an argument x and returns the value of x + 1. The type inferred for succ is int -> int which means it is a function from int to int -- it takes an integer argument and returns an integer.

You can also provide explcit type annotations, but generally we elide them.

```OCaml
let succ (x : int) : int = x + 1
```

    val succ : int -> int = <fun>

The latter definition of `succ` shadows the former.

### Multiple arguments

Functions with multiple arguments are defined the same way:

```OCaml
let add x y = x + y
```

    val add : int -> int -> int = <fun>

### Function application

Unlike most imperative languages, functions are applied without any brackets:

```OCaml
let b = succ 8

let c = add a b
```

    val b : int = 9

    val c : int = 16

  Exercise

Implement a function to compute the sum of successors of the given two numbers using `add` and `succ`.

```OCaml
let sum_of_succ x y = failwith "for you to implement"
```

    val sum_of_succ : 'a -> 'b -> 'c = <fun>

```OCaml
assert (sum_of_succ 5 6 = 13)
```

### Recursive functions

We can also create recursive functions by adding the rec keyword to a let binding. For example, the sum of first `n` integers can be implemented as follows:

```OCaml
let rec sum_of_first_n n =
  if n <= 0 then 0
  else sum_of_first_n (n-1) + n
```

    val sum_of_first_n : int -> int = <fun>

```OCaml
assert (sum_of_first_n 5 = 15)
```

    - : unit = ()

  Exercise

Implement a recursive function that computes the nth fibonacci number.

\begin{align}
fib(n) =
  \begin{cases}
    1 & \quad \text{if } n < 2 \\
    fib(n-1) + fib(n-2)       & \quad \text{otherwise}
  \end{cases}
\end{align}

```OCaml
let rec fib n = failwith "for you to implement"
```

    val fib : 'a -> 'b = <fun>

```OCaml
assert (fib 10 = 89)
```

### Labelled arguments

Consider the following function

```OCaml
let divide dividend divisor = dividend / divisor
```

    val divide : int -> int -> int = <fun>

Looking at just the signature, it's not obvious which int argument is the dividend and which is the divisor.

We can fix this using labelled arguments. To label an argument in a signature, `NAME:` is put before the type. When defining the function, we put a tilde (`~`) before the name of the argument:

```OCaml
let divide ~dividend ~divisor = dividend / divisor
```

    val divide : dividend:int -> divisor:int -> int = <fun>

We can then call it using:

```OCaml
divide ~dividend:9 ~divisor:3
```

    - : int = 3

Labelled arguments can be passed in in any order (!)

```OCaml
divide ~divisor:3 ~dividend:9
```

    - : int = 3

We can also pass variables into the labelled argument:

```OCaml
let dividend = 9 in
let divisor  = 3 in
divide ~dividend:dividend ~divisor:divisor
```

    - : int = 3

If the variable name happens to be the same as the labelled argument, we don't even have to write it twice:

```OCaml
let dividend = 9 in
let divisor  = 3 in
divide ~dividend ~divisor
```

    - : int = 3

  Exercise

Implement `modulo ~dividend ~divisor` using our version of divide with labelled arguments.

```OCaml
let modulo ~dividend ~divisor = failwith "for you to implement"
```

    val modulo : dividend:'a -> divisor:'b -> 'c = <fun>

```OCaml
assert (2 = modulo ~dividend:17 ~divisor:5)
```

```OCaml
assert (0 = modulo ~dividend:99 ~divisor:9)
```

### Higher-order functions

Since OCaml is a functional language, functions are regular values which can be used like any other. In particular, they can be used as arguments to other functions. Functions which take other functions as arguments as called higher-order functions.

For example, the `List.map` function takes two arguments: a function and a list, and returns a new list created by applying the function to each of the elements of the list.

We can use `List.map` to apply the succ function to all the numbers in the list  `[1; 2; 3]`:

```OCaml
let l = List.map succ [1;2;3]
```

    val l : int list = [2; 3; 4]

This jupyter notebook comes equipped with `merlin`, an OCaml IDE service plugin that provides auto-completion, documentation search, etc. Using merlin, you can look up the available functions in `List` by typing `List.<tab>`.

You can also get documentation for a particular function by typing the function and pressing `shift+tab`. For example, try typing `List.map<shift+tab>`. A pop up should appear displaying the documentation.

```OCaml
List.map
```

    - : ('a -> 'b) -> 'a list -> 'b list = <fun>

### Currying

Like many functional languages, OCaml provides support for partial application of functions in the form of currying.

You may have noticed that the type of our add function was written:

`int -> int -> int`

another way to write this type would be

`int -> (int -> int)`.

In other words, add is acutally a function which takes an int and returns a function from int to int. For example, we could redefine our succ function by partially applying add to 1:

```OCaml
let succ = add 1
```

    val succ : int -> int = <fun>

### Anonymous functions

Instead of defining each function with a let, often times it is handy to define functions on the fly. OCaml has support for anonymous functions, which allows you to define unnamed functions. To write an anonymous function, the `fun` keyword is used in the following form `(fun ARG1 ARG2 ... -> BODY)`. We can define an anonymous function for `succ` and use it as follows:

```OCaml
List.map (fun x -> x + 1) [1;2;3]
```

    - : int list = [2; 3; 4]


# Unit Testing Functions Reference

## Author: Kevin Lituchy

## Introduction:
This module contains in-depth explanations of all the functions in `UnitTesting`.If you have not already, please read through the Jupyter notebook [tutorial](../Tutorial-UnitTesting.ipynb) for unit testing. This will contain in-depth information on all functions used for unit testing, not a high-level user tutorial. With examples, the default module that will be used is `UnitTesting/Test_UnitTesting/test_module.py`.

# Table of Contents
$$\label{toc}$$

This module is organized as follows:

1. [`Non-interactive Files`](#non_interactive_files)
    1. [`failed_tests`](#failed_tests)
    1. [`standard_constants`](#standard_constants)
1. [`run_NRPy_UnitTests`](#run_NRPy_UnitTests)
1. [`create_test`](#create_test)
    1. [`setup_trusted_values_dict`](#setup_trusted_values_dict)
    1. [`RepeatedTimer`](#RepeatedTimer)
1. [`run_test`](#run_test)
    1. [`evaluate_globals`](#evaluate_globals)
    1. [`cse_simplify_and_evaluate_sympy_expressions`](#cse_simplify_and_evaluate_sympy_expressions)
        1. [`expand_variable_dict`](#expand_variable_dict)
        1. [`get_variable_dimension`](#get_variable_dimension)
        1. [`flatten`](#flatten)
        1. [`form_string`](#form_string)
        1. [`increment_counter`](#increment_counter)
        1. [`calculate_value`](#calculate_value)
    1. [`create_dict_string`](#create_dict_string)
    1. [`first_time_print`](#first_time_print)
    1. [`calc_error`](#calc_error)

# `Non-interactive Files` \[Back to [top](#toc)\]
$$\label{non_interactive_files}$$

## `failed_tests` \[Back to [top](#toc)\]
$$\label{failed_tests}$$

[`failed_tests.txt`](../../edit/UnitTesting/failed_tests.txt) is a simple text file that keeps track of which tests
failed. Line 1 is by default 'Failures: '. The subsequent lines tell the
user which test functions in which test files failed in the following
format: `[test file path]: [test function]`

Example:

Say that the test function `test_module_for_testing_no_gamma()` failed.
Then we'd expect `failed_tests.txt` to be the following:

```
Failures:

UnitTesting/Test_UnitTesting/test_module.py: test_module_for_testing_no_gamma
```

## `standard_constants` \[Back to [top](#toc)\]
$$\label{standard_constants}$$

[`standard_constants.py`](../../edit/UnitTesting/standard_constants.py) stores test-wide information that the user can
modify to impact the numerical result for their globals. It currently
only has one field, `precision`, which determines how precise the values
for the globals are. It is by default set to `30`, which we've
determined to be a reasonable amount. This file has the ability to be
expanded upon in the future, but it is currently minimal.

# `run_NRPy_UnitTests` \[Back to [top](#toc)\]
$$\label{run_NRPy_UnitTests}$$

[`run_NRPy_UnitTests.sh`](../../edit/UnitTesting/run_NRPy_UnitTests.sh) is a bash script that acts as the hub for
running tests -- it's where the user specifies the tests they'd like to
be run. It keeps track of which tests failed by interacting with
[failed_tests](#failed_tests), giving the user easily readable output
from the file. It also has the option to automatically rerun the tests
that failed in `DEBUG` mode if the boolean `rerun_if_fail` is `true`.

The script is run with the following syntax:

```
./UnitTesting/run_NRPy_UnitTests.sh [python interpreter]
```

This of course assumes that the user is in the nrpy directory; the user
simply has to specify the path from their current directory to the bash
file.

Examples of `python interpreter` are `python` and `python3`.

The script first lets the user know if they forgot to pass a python
interpreter. Then if they didn't, it prints some baseline information
about Python variables: `PYTHONPATH`, `PYTHONEXEC`, and `PYTHONEXEC`
version.

`failed_tests.txt` is then overwritten with the default information.
This makes it so that each subsequent test call has a unique list of the
tests that passed; it wouldn't make sense to store this information.

The user can then change the boolean `rerun_if_fail` if need be. Next,
the user can add tests using the `add_test` function. The syntax is as
follows: `add_test [path to test file]`

Example:

```
add_test UnitTesting/Test_UnitTesting/test_module.py
```

Finally, the bash script will read any failures from `failed_tests.txt`
and, if `rerun_if_fail` is `true`, rerun those tests. It lastly prints
which tests failed in the same format as `failed_tests.txt`, and if no
tests failed, a success message.

# `create_test` \[Back to [top](#toc)\]
$$\label{create_test}$$

[`create_test`](../../edit/UnitTesting/create_test.py) is a function that takes the following user-supplied
information:

- `module`, the module to be tested
- `module_name`, the name of the module
- `function_and_global_dict`, a dictionary whose keys are functions and whose values are lists of globals

It uses this information to generate a test file that is automatically run by the bash
script; this test file does all the heavy lifting in calling the
function, getting expressions for all the globals, evaluating the
expressions to numerical values, and storing the values in the proper
trusted_values_dict.

`create_test` additionally takes optional arguments `logging_level` and
`initialization_string_dict`, which respectively determine the desired
level of output (think verbosity) and run some Python code prior calling
the specified function. Usage is as following:

```
module = 'BSSN.BrillLindquist'

module_name = 'BrillLindquist'

function_and_global_dict = {'BrillLindquist(ComputeADMGlobalsOnly = True)': ['alphaCart', 'betaCartU', 'BCartU', 'gammaCartDD', 'KCartDD']}

create_test(module, module_name, function_and_global_dict)
```

The way to think of this is that the module to be tested is
BSSN.BrillLindquist. The module_name is how you refer to this module --
it's a bit arbitrary, so whether you prefer BrillLindquist or bl, it
won't change the computation. The function_and_global_dict contains
entry 'BrillLindquist(ComputeADMGlobalsOnly = True)', which is the
function that gets called in the module. It's value in the dictionary is
a list of globals that get created when this function gets called.

Now let's add the optional arguments into the same example:

```
module = 'BSSN.BrillLindquist'

module_name = 'BrillLindquist'

function_and_global_dict = {'BrillLindquist(ComputeADMGlobalsOnly = True)': ['alphaCart', 'betaCartU', 'BCartU', 'gammaCartDD', 'KCartDD']}

logging_level = 'DEBUG'

initialization_string_dict = {'BrillLindquist(ComputeADMGlobalsOnly = True)': 'print("example")\nprint("Hello world!")'}

create_test(module, module_name, function_and_global_dict, logging_level=logging_level, initialization_string_dict=initialization_string_dict)
```

Now when create_test runs, the user will be given much more output due
to the logging_level; additionally, the user-specified print will occur
due to initialization_string_dict.

You may now be wondering why we use dictionaries to store this data
instead of simply having separate variables `function`, `global_list`,
and `initialization_string`. This is where some of the power of this
testing method lies: we can test multiple functions and their globals
with ease! In other words, function_and_global_dict can contain multiple
entries, each a specific function call with its own associated list of
globals. Since not every function being tested must have an associated
initialization_string, we make an entry for each function optional. An
example is as follows:

```
module = 'BSSN.BrillLindquist'

module_name = 'BrillLindquist'

function_and_global_dict = {'BrillLindquist(ComputeADMGlobalsOnly = True)': ['alphaCart', 'betaCartU', 'BCartU', 'gammaCartDD', 'KCartDD'],
                            'BrillLindquist(ComputeADMGlobalsOnly = False)': ['alphaCart', 'betaCartU', 'BCartU', 'gammaCartDD', 'KCartDD']}

logging_level = 'DEBUG'

initialization_string_dict = {'BrillLindquist(ComputeADMGlobalsOnly = True)': 'print("example")\nprint("Hello world!")'}

create_test(module, module_name, function_and_global_dict, logging_level=logging_level, initialization_string_dict=initialization_string_dict)
```

Both instances will be called separately, with their own globals. The
print statements will only be called in the first function, since there
is no associated initialization_string for the second function as well.

An important note when using `create_test` is that all arguments are
**strings**. This includes the module, module_name, function, each
global in the list of globals, logging level, and initialization_string.
The reason for making these fields strings is that when setting
module_name, for example, there doesn't exist anything in Python with
the name BrillLindquist. So, we wrap it in a string. This is true of
every input. Be careful with the dicts and lists, however: their
arguments are strings, they aren't themselves strings.

So what does this funciton actually do at a lower level? First, `create_test` makes sure that all user arguments are of the correct type, failing if any are incorrect.

It then loops through every function in `function_and_global_dict`, and creates `file_string`, a string that represents a unit test file that will be executed. Along with the current function comes its global list, and initialization string if it has one.

Next, the contents from [run_test](#run_test) is copied into `file_string` so that the test will be automatically run, and so the user can easily see their unique file contents in case of an error.

A file is then created which houses the `file_string`, and is what gets called with a bash script. The file exists in the directory of the test being run, and is deleted upon test success, but left for the user to inspect upon test failure. `file_string` has code to call [setup_trusted_values_dict](#setup_trusted_values_dict), initialize [RepeatedTimer](#RepeatedTimer), and runs [run_test](#run_test) in order to ensure that the test will run correctly.

Finally, the test file is called using [cmdline_helper](../../edit/cmdline_helper.py), which runs the test and does everything described in [run_test](#run_test).

Once `run_test` finishes, either the test failed or the test succeeded. `file_string` has additonal code to create a `success.txt` file if the test passes, and do nothing otherwise. So, `create_test` looks for the existence of `success.txt`. If it exists, we delete it and create_test has finished for the current function and moves on to the next function. Otherwise, if `success.txt` doesn't exist, an exception is thrown to be caught later.

## `setup_trusted_values_dict` \[Back to [top](#toc)\]
$$\label{setup_trusted_values_dict}$$

[`setup_trusted_values_dict`](../../edit/UnitTesting/setup_trusted_values_dict.py) takes in a path to a test directory `path`,
and checks whether or not a `trusted_values_dict.py` exists in the test
directory. If it does exist, the function does nothing. If it doesn't
exist, `setup_trusted_values_dict` creates the file
`trusted_values_dict.py` in the test directory. In then writes the
following default code into the file:

```
from mpmath import mpf, mp, mpc
from UnitTesting.standard_constants import precision

mp.dps = precision
trusted_values_dict = {}

```

The default code allows the unit test to properly interact with and
write to the file.

## `RepeatedTimer` \[Back to [top](#toc)\]
$$\label{RepeatedTimer}$$

[`RepeatedTimer`](../../edit/UnitTesting/RepeatedTimer.py) is a class that allows the user to automatically run some function every `n` seconds. We specifically use the class for timed output, where we print every five minutes in order to prevent time-outs in Travis CI; if Travis CI doesn't receive any output for too long, the build automatically fails.
Due to some NRPy modules taking a long time due to their sheer size, we want to ensure that the build doesn't time-out simply due to it taking a long time.

# `run_test` \[Back to [top](#toc)\]
$$\label{run_test}$$

[`run_test`](../../edit/UnitTesting/run_test.py) acts as the hub for an individual unit test. It takes in all
the module-wide information, and goes through all the steps of
determining whether the test passed or failed by calling many
sub-functions. A fundamentally important part of `run_test` is the
notion of `self`; `self` stores a test's information (i.e. `module`,
`module_name`, etc.) to be able to easily pass information to and make
assertions in sub-functions. When `self` is referenced, simply think
"information storage".

`run_test` begins by importing the `trusted_values_dict` of the current
module being tested; since `setup_trusted_values_dict` is called before
`run_test`, we know it exists.

`run_test` then determines if the current function/module is being done
for the first time based off the existence of the proper entry in
`trusted_values_dict`, and stores this boolean in `first_time`.

[`evaluate_globals`](#evaluate_globals) is then run in order to generate
the SymPy expressions for each global being tested.

Next,
[`cse_simplify_and_evaluate_sympy_expressions`](#cse_simplify_and_evaluate_sympy_expressions)
is called to turn each SymPy expression for each global into a random, yet predictable/repeatable, number.

The next step depends on the value of `first_time`: if `first_time` is `True`, then [`first_time_print`](#first_time_print) is run to print the result both to the console and to the `trusted_values_dict.py`. Otherwise, if `first_time` is `False`, [`calc_error`](#calc_error) is called in order to compare the calculated values and the trusted values for the current module/function. If an error was found, the difference is printed and the code exits. Otherwise, the module completes and returns.

On it's own, `run_test` doesn't do much -- it's the subfunctions called by `run_test` that do the heavy lifting in terms of formatting, printing, calculating, etc.

## `evaluate_globals` \[Back to [top](#toc)\]
$$\label{evaluate_globals}$$

[`evaluate_globals`](../../edit/UnitTesting/evaluate_globals.py) takes in `self` and uses the following attributes:

- `self.module`
- `self.module_name`
- `self.initialization_string`
- `self.function`
- `self.global_list`

`evaluate_globals` first imports `self.module` as a module object, instead of a simple string. It next runs `self.initialization_string`, then creates string of execution `string_exec` to be called; this string of execution calls `self.function` on `self.module`, then gets the SymPy expressions for all globals defined in `self.global_list` and returns a dictionary containing all the globals and their expressions.

## `cse_simplify_and_evaluate_sympy_expressions` \[Back to [top](#toc)\]
$$\label{cse_simplify_and_evaluate_sympy_expressions}$$

[`cse_simplify_and_evaluate_sympy_expressions`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in `self` and uses the following attributes:

- `self.variable-dict`

`cse_simplify_and_evaluate_sympy_expressions` uses SymPy's cse algorithm to efficiently calculate a value for each expression by assigning a random, yet predictable and consistent, number to each variable in the variable dictionary.

`cse_simplify_and_evaluate_sympy_expressions` first calls [`expand_variable_dict`](#expand_variable_dict) on `self.variable_dict` to expand the variable dictionary. This makes it much easier for the user to figure out which variables differ, if any.
Basic example:

```
variable_dict = {'betaU': [0, 10, 400]}
expand_variable_dict(variable_dict) --> {'betaU[0]': 0, 'betaU[1]: 10, 'betaU[2]': 400}

```

This may seem trivial and unnecessary for a small example, but once the tensors get to a higher rank, such as `GammahatUDDdD`, which is rank 5 by NRPy naming convention, it's easy to see why the expansion is necessary for user clarity.

Next, `cse_simplify_and_evaluate_sympy_expressions` loops through each variable in the expanded variable dict and adds that variable's free symbols to a set containing all free symbols from all variables. 'Free symbols' are simply the SymPy symbols that make up a variable.

Once we get this set of free symbols, we know we have every symbol that will be referenced when substituting in values. So, we assign each symbol in this set to a random value. To ensure that this remains predictable and consistent, we do the following:

- Create a string representation of the symbol
- Use Python's hashlib module to hash the string
- Turn the hash value into a hex number
- Turn the hex number into an decimal number
- Pass the decimal number into Python's random module as the seed
- Assign the next random number in the given seed to the symbol

This method ensures a symbol will always be assigned the same random value throughout Python instances, operating systems, and Python versions. If the symbol is `M_PI` or `M_SQRT1_2`, however, we want to assign them to their exact values; they should be given their true values of `pi` and `1/sqrt(2)`, respectively.

`cse_simplify_and_evaluate_sympy_expressions` then loops through the expanded variable dictionary in order to calculate a value for each variable. In order to optimize the calculation for massive expressions, we use SymPy's cse ([common subexpression elimination](https://en.wikipedia.org/wiki/Common_subexpression_elimination)) algorithm to greatly improve the speed of calculation. What this algorithm does in essence is factor out common subexpressions (i.e. `a**2`) by storing them in their own variables (i.e. `x0 = a**2`) so that any time `a**2` shows up, we don't have to recalculate the value of the subexpression; we instead just replace it with `x0`. This is a seemingly small optimization, but as NRPy expressions can become massive, the small efficiencies add up and make the calculation orders of magnitude faster.

Once the cse algorithm optimizes the calculation for a given variable, we now calculate a numerical result for the variable using [`calculate_value`](#calculate_value) and store it in a calculated dictionary. For numerical results  near zero, we double check the calculation at a higher precision to see if the value should truly be zero.

Finally, after repeating this process for each variable, we return the calculated dictionary which stores numerical values for each variable.

### `expand_variable_dict` \[Back to [top](#toc)\]
$$\label{expand_variable_dict}$$

[`expand_variable_dict`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a variable dictionary `variable_dict` , and returns an expanded variable dictionary. 'expanded' refers to taking all tensors in `variable_dict` and breaking them down into their subcomponents according to the indices of the tensor. This is best illustrated with an example:

```
variable_dict = {'alpha': 0, 'betaU': [3.14, 1, -42]}
expand_variable_dict(variable_dict) --> {'alpha': 0, 'betaU[0]': 3.14, 'betaU[1]': 1, 'betaU[2]' = -42}

variable_dict = {'aDD': [[1, 2, 3], [4, 5, 6], [7, 8, 9]]}
expanded_variable_dict(variable_dict) --> {'aDD[0][0]': 1, 'aDD[0][1]': 2, 'aDD[0][2]': 3, 'aDD[1][0]': 4, 'aDD[1][1]': 5, 'aDD[1][2]': 6, 'aDD[2][0]': 7, 'aDD[2][1]': 8, 'aDD[2][2]': 9}
```

As we can see, `expand_variable_dict` breaks up tensors into their indices. While this may not be obviously useful for low-rank tensors, high-rank tensors become overwhelmingly difficult to debug, and as such their expansion greatly eases the debugging process.

`expand_variable_dict` starts out by looping through each variable in `variable_dict`. For each variable, it first gets the dimension of the variable's expression list using [`get_variable_dimension`](#get_variable_dimension) -- this is equivalent to getting the rank of the tensor.

`expand_variable_dict` then initializes a counter of the correct dimension; the counter represents the current index of the expression list.

Next, `expand_variable_dict` flattens the expression list into a rank-1 tensor using [`flatten`](#flatten); this makes it simple to iterate through.

The flattened expression list is then iterated through, and each expression in the expression list is stored in a result dictionary `result_dict`. To get the key for the entry into `result_dict`, we pass the current variable and the counter into ['form_string'](#form_string), which gives us a string representation of an index of a variable. The value for the respective key is simply the current expression.

The counter is then incremented using [`increment_counter`](#increment_counter) to ensure a consistent naming scheme.

This process is repeated for all variables, and finally `result_dict` is returned.

### `get_variable_dimension` \[Back to [top](#toc)\]
$$\label{get_variable_dimension}$$

[`get_variable_dimension`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a tensor `tensor` and returns a tuple containing the rank of `tensor` and the dimension of `tensor`. It does this by looping through the first element of the tensor until it's rank-0. Then the number of times it had to loop is the rank of the tensor. The dimension of the tensor is simply the length of the rank-1 tensor. Example:

```
tensor = 42
get_variable_dimension(tensor) --> 0, 1

tensor = [1, 2, 3, 4, 5]
get_variable_dimension(tensor) --> 1, 5

tensor = [[1, 2], [3, 4]] --> 2, 2
get_variable_dimension(tensor) --> 2, 2
```

`get_variable_dimension` assumes that `tensor` has the same dimension at all ranks.

This means it's square, or it's dimension could be written `N x N x ... x N`.

### `flatten` \[Back to [top](#toc)\]
$$\label{flatten}$$

[`flatten`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a list `l` and an optional argument the represents already flattened list `fl`. The user need not pay attention to `fl`: it's simply used for the recursive call, so the user should use `flatten` with only `l` as an argument. It 'unwraps' each element of `l` by recursively calling `flatten` while the current index of the current element is of type `list`. Once it's not of type list, append it to `fl`, and once every element has been flattened, return `fl`. Example:

```
l = [1, 2, 3]
flatten(l) --> [1, 2, 3]

l = [[1, 2], [3, 4]]
flatten(l) --> [1, 2, 3, 4]

l = [[[[[2], 3], 4, [5, 6], 7]], 8]
flatten(l) --> [2, 3, 4, 5, 6, 7, 8]
```

### `form_string` \[Back to [top](#toc)\]
$$\label{form_string}$$

[`form_string`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a variable `var` and a counter `counter` and returns the string representation of the `counter`'th index of `var`. Example:

```
var = 'alpha'
counter = [0, 0]
form_string(var, counter) --> 'alpha[0][0]'

var = 'gammauDDdD'
counter = [2, 3, 4, 1, 0]
form_string(var_counter) --> 'gammauDDdD[2][3][4][1][0]'
```

### `increment_counter` \[Back to [top](#toc)\]
$$\label{increment_counter}$$

[`increment_counter`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a counter `counter` and a length `length` and returns a new counter which is equivalent to (`counter` + 1) in base `length`.

`increment_counter` loops through `counter` in reverse, adds `1` to the last digit, and then checks if any digit is now equal to `length` -- if it is, increment the next digit as well, and so on.

It then returns the un-reversed new counter which represents an iteration of `counter`.

Example:

```
counter = [0, 0]
length = 2
increment_counter(counter, length) -> [0, 1]

counter = [0, 1]
length = 2
increment_counter(counter, length) -> [1, 0]

counter = [2, 3, 4, 4, 4]
length = 5
increment_counter(counter, length) -> [2, 4, 0, 0, 0]
```

### `calculate_value` \[Back to [top](#toc)\]
$$\label{calculate_value}$$

[`calculate_value`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a dictionary of free symbols `free_symbols_dict`, the outputs from SymPy's cse algorithm `replaced` and `reduced`, and an optional argument `precision_factor` which is `1` by default.

`calculate_value` first sets `reduced` to `reduced[0]` -- this is to remove extraneous output from the cse algorithm. It then sets the precision to `standard_constants.precision * precision_factor`. This is why `precision_factor` is optional and defaults to `1` -- most of the time we want the standard precision.

`calculate_value` next loops through `replaced`. `replaced` is a dictionary whose keys are new expressions and whose values are old expressions; in essence, we set the new expression to the value we get by calculating the old expression. This is equivalent to calculating numerical values for all the cse optimizations instead of expressions.

Now that we have values for all the new expressions, we can substitute these into the overall expression given to us by `reduced`. After doing this, we finally have a value for our expression that we arrived at as optimally as possible.

Finally, we store this value as an `mpf` -- if it is actually complex, we store it as a `mpc`. The precision is then set back to `standard_constants.precision` before the final value is returned.

## `create_dict_string` \[Back to [top](#toc)\]
$$\label{create_dict_string}$$

[`create_dict_string`](../../edit/UnitTesting/cse_simplify_and_evaluate_sympy_expressions.py) takes in a dictonary of values and returns a well-formatted string representation of the dictionary. It ensures that a consistent, repeatable output is returned from two identical dictionaries.

`create_dict_string` sorts the dictionary of values, loops through each (key, value) pair of the dictionary, and creates a string based on the type of the value (mpf, mpc, or other). By doing this, it creates a string representation of the dictionary of values that can be printed to a `trusted_values-dict`.

## `first_time_print` \[Back to [top](#toc)\]
$$\label{first_time_print}$$

[`first_time_print`](../../edit/UnitTesting/first_time_print.py) takes in `self` and a boolean, `write`, and uses the following attributes:

- `self.module_name`
- `self.trusted_values_dict_name`
- `self.calculated_dict`
- `self.path`

`first_time_print` prints the string that should be copied into your `trusted_values_dict` to the console. If `write` is `True`, it additionally automatically appends the string to the `trusted_values_dict.py`.

## `calc_error` \[Back to [top](#toc)\]
$$\label{calc_error}$$

[`calc_error`](../../edit/UnitTesting/calc_error.py) takes in `self` and uses the following attributes:

- `self.calculated_dict`
- `self.trusted_values_dict_entry`
- `self.module_name`

`calc_error` loops through each variable in `self.calculated_dict` and `self.trusted_values_dict_entry`, and compares the variables' values to ensure that no variable differs.

`calc_error` first makes sure that `self.calculated_dict` and `self.trusted_values_dict_entry` have the same entries; that is, they contain values for the same variables. If any variables differ, those variables are printed and the function returns `False`.

If the dictionaries have the same entries, we must compare the two values for a given variable. We compare the values by seeing by how many decimal places the values differ; if they differ by more than (`standard_constants.precision` / 2) decimal places, then we consider the values to be different. The reason for this method of comparison is the inconsistency of floating point calculations; if we simply checked for equality, we'd consistently run into error when in reality the values differed by a minimal amount -- say `2 * 10 ** -30` -- which is close enough to have arisen from the same calculation.

We repeat this process for each variable, storing the variables who differed in a list. After each variable has been checked, we see if the list of differing variables is empty. If it's empty, no variables differed -- so the test passed -- and we return `True`. Otherwise, if it's not empty, we print the contents of the list -- the variables that differed. We additionally print a new `trusted_values_dict` entry (similar to [first_time_print](#first_time_print) that the user can look at and determine if it's correct or not. The function then returns `False`, as the test failed.


# Array

Array is a container which can hold a fix number of items and these items should be of the same type.

```
arrayName = array(typecode, [Initializers])
```
 Typecode are the codes that are used to define the type of value the array will hold. Some common typecodes used are as follows

 | Typecode | Value |
 |---|---|
 | b	| Represents signed integer of size 1 byte |
 | B	| Represents unsigned integer of size 1 byte |
 | c	| Represents character of size 1 byte |
 | i	| Represents signed integer of size 2 bytes |
 | I	| Represents unsigned integer of size 2 bytes |
 | f	| Represents floating point of size 4 bytes |
 | d	| Represents floating point of size 8 bytes |

```python
# creates an array named array1
from array import *
array1 = array('i', [10,20,30,40,50])
for x in array1:
    print(x)
```

    10
    20
    30
    40
    50

```python
## Accessing Array Element
print(f"The first element: {array1[0]}")
print(f"The first two element: {array1[:2]}")
print(f"The middle two element: {array1[1:4]}")
print(f"The last element: {array1[-1]}")
print(f"The last three element: {array1[-4:]}")
```

    The first element: 10
    The first two element: array('i', [10, 20])
    The middle two element: array('i', [20, 30, 40])
    The last element: 50
    The last three element: array('i', [20, 30, 40, 50])

```python
# Insertion Operation
# Insert operation is to insert one or more data elements into an array. Based on the requirement,
# a new element can be added at the beginning, end, or any given index of array.

print(f"Original array: {array1}")
array1.insert(1,60)
print(f"revised array: {array1}")
```

    Original array: array('i', [10, 20, 30, 40, 50])
    revised array: array('i', [10, 60, 20, 30, 40, 50])

## Deletion Operation

Deletion refers to removing first one existing element from the array and re-organizing all elements of an array.

print(f"Original array: {array1}")
array1.remove(60)
print(f"revised array: {array1}")

```python
# Search Operation
# You can perform a search for an array element based on its value or its index.
print (array1.index(50))
```

    4

```python
# Update Operation
# Update operation refers to updating an existing element from the array at a given index.

print(f"Original array: {array1}")
array1[2] = 80
print(f"revised array: {array1}")
```

    Original array: array('i', [10, 20, 30, 40, 50])
    revised array: array('i', [10, 20, 80, 40, 50])

# List

The list is a most versatile datatype available in Python which can be written as a list of comma-separated values (items) between square brackets.

**Important thing about a list is that items in a list need not be of the same type, while for a array they should be same type**

```python
# create lists

list1 = ['physics', 'chemistry', 1997, 2000]
list2 = [1, 2, 3, 4, 5 ]
list3 = ["a", "b", "c", "d"]

print(f"list1: {list1}")
print(f"list2: {list2}")
print(f"list3: {list3}")
```

    list1: ['physics', 'chemistry', 1997, 2000]
    list2: [1, 2, 3, 4, 5]
    list3: ['a', 'b', 'c', 'd']

```python
# Accessing Values
# To access values in lists, use the square brackets for slicing along with the index
# or indices to obtain value available at that index.
print("list1[0]: ", list1[0])
print("list2[1:5]: ", list2[1:5])
```

    list1[0]:  physics
    list2[1:5]:  [2, 3, 4, 5]

```python
# Updating Lists
# You can update single or multiple elements of lists by giving the slice on the left-hand side of the assignment operator
print("Value available at index 2 : ", list1[2])
list1[2] = 2001
print("New value available at index 2 : ", list1[2])
```

    Value available at index 2 :  1997
    New value available at index 2 :  2001

# Tuple

A tuple is a sequence of immutable Python objects. Tuples are sequences, just like lists. The differences between tuples and lists:
- the tuples cannot be changed unlike lists
- tuples use parentheses, (a, b, c), whereas lists use square brackets, [a, b, c].

```python
# Updating Tuples

# Tuples are immutable which means you cannot update or change the values of tuple elements.
# You are able to take portions of existing tuples to create new tuples as the following example demonstrates

tup1 = (12, 34.56)
tup2 = ('abc', 'xyz')

# So let's create a new tuple as follows
tup3 = tup1 + tup2
print(f"New tuple: {tup3}")

# Following action is not valid for tuples
tup1[0] = 100
```

```python
# Delete Tuple Elements

# Removing individual tuple elements is not possible.
# There is, of course, nothing wrong with putting together
# another tuple with the undesired elements discarded.

# To explicitly remove an entire tuple, just use the del statement.
```

# Dictionary

- In Dictionary each key is separated from its value by a colon (:)
- the items are separated by commas
- the whole thing is enclosed in curly braces.
- An empty dictionary without any items is written with just two curly braces, like this {}.

```python
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
print("dict['Name']: ", dict['Name'])
print("dict['Age']: ", dict['Age'])
```

    dict['Name']:  Zara
    dict['Age']:  7

# ChainMap

It is a type of data structure to manage multiple dictionaries together as one unit.
- Removing duplicate keys. If there are duplicate keys, then only the value from the first key is preserved.
- The best use of ChainMap is to search through multiple dictionaries at a time and get the proper key-value pair mapping
- We also see that these ChainMaps behave as stack data structure.

```python
# Examples

import collections

dict1 = {'day1': 'Mon', 'day2': 'Tue'}
dict2 = {'day3': 'Wed', 'day1': 'Thu'}

res = collections.ChainMap(dict1, dict2)
print(res)
```

    ChainMap({'day1': 'Mon', 'day2': 'Tue'}, {'day3': 'Wed', 'day1': 'Thu'})

```python
# Creating a single dictionary
print(res.maps,'\n')

print('Keys = {}'.format(list(res.keys())))
print('Values = {}'.format(list(res.values())))
print()
```

    [{'day1': 'Mon', 'day2': 'Tue'}, {'day3': 'Wed', 'day1': 'Thu'}]

    Keys = ['day3', 'day1', 'day2']
    Values = ['Wed', 'Mon', 'Tue']

```python
# Print all the elements from the result
print('elements:')
for key, val in res.items():
   print('{} = {}'.format(key, val))
print()
```

    elements:
    day3 = Wed
    day1 = Mon
    day2 = Tue

```python
# Find a specific value in the result
print('day3 in res: {}'.format(('day1' in res)))
print('day4 in res: {}'.format(('day4' in res)))
```

    day3 in res: True
    day4 in res: False

```python
# Updating Map
# When the element of the dictionary is updated, the result is instantly updated in
# the result of the ChainMap. In the below example we see that the new updated value
# reflects in the result without explicitly applying the ChainMap method again.

print(res.maps,'\n')

dict2['day4'] = 'Fri'

print(res.maps,'\n')
```

    [{'day1': 'Mon', 'day2': 'Tue'}, {'day3': 'Wed', 'day1': 'Thu'}]

    [{'day1': 'Mon', 'day2': 'Tue'}, {'day3': 'Wed', 'day1': 'Thu', 'day4': 'Fri'}]

# 链表

1) 含义：链表（Linked list）是一种常见的基础数据结构，是一种线性表，但是并不会按线性的顺序存储数据，而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储，链表在插入的时候可以达到O(1)的复杂度，比另一种线性表顺序表快得多，但是查找一个节点或者访问特定编号的节点则需要O(n)的时间，而顺序表相应的时间复杂度分别是O(logn)和O(1)

2) 特点：使用链表结构可以克服数组链表需要预先知道数据大小的缺点，链表结构可以充分利用计算机内存空间，实现灵活的内存动态管理。但是链表失去了数组随机读取的优点，同时链表由于增加了结点的指针域，空间开销比较大

3) 操作：
1. is_empty() 链表是否为空
3. length() 链表长度
3. travel() 遍历链表
4. add(item) 链表头部添加
5. append(item) 链表尾部添加
6. insert(pos, item) 指定位置添加
7. remove(item) 删除节点
8. search(item) 查找节点是否存在

```python
class LinkNode(object):
    def __init(self, item, prev=None, next=None):
        self.item = item
        self.prev = prev
        self.next = next
```

```python
class DLinkList(object):
    def __init__(self):
        self.head = None

        self.count = 0

    def add(self, item):
        node = LinkNode(item)

        if self.head == None:
            self.head = node
            node.prev = node
            node.next = node
        else:
            node.next = self.head
            self.head.prev = node
            self.head = node
        self.count += 1

    def append(self, item):
        pass

    def is_empty(self):
        return self._head == None

    def length(self):
        return self.count

```

# 堆栈

1. 含义：堆栈（英语：stack），也可直接称栈，在计算机科学中，是一种特殊的串列形式的数据结构，它的特殊之处在于只能允许在链接串列或阵列的一端（称为堆叠顶端指标，英语：top）进行加入资料（英语：push）和输出资料（英语：pop）的运算。另外堆叠也可以用一维阵列或连结串列的形式来完成。堆叠的另外一个相对的操作方式称为伫列；由于堆叠数据结构只允许在一端进行操作，因而按照后进先出（LIFO, Last In First Out）的原理运作

2. 特点：先入后出，后入先出；除头尾节点之外，每个元素有一个前驱，一个后继

```python
class Stack(object):
    def __init__(self):
        self.data = []

    def length(self):
        return len(self.data)

    def is_empty(self):
        return self.length == 0

    def push(self, item):
        self.data.append(item)

    def pop(self, item):
        return self.data.pop()
```

# 队列

1) 含义：和堆栈类似，唯一的区别是队列只能在队头进行出队操作，所以队列是是先进先出（FIFO, First-In-First-Out）的线性表

2) 特点：先入先出,后入后出；除尾节点外,每个节点有一个后继；（可选）除头节点外,每个节点有一个前驱

```python
class Queue(object):
    def __init__(self):
        self.data = []

    def dequeue(self):
        return self.data.pop(0) if self.data != [] else None
    def inqueue(self, item):
        self.data.append(item)
```

# Dequeue

A double-ended queue, or deque, supports adding and removing elements from either end. he more commonly used stacks and queues are degenerate forms of deques, where the inputs and outputs are restricted to a single end.

```python
import collections

dq = collections.deque(["Monday","Tuesday", "Wesday", "Thursday"])

print(f"Double ended queue: {dq}")

dq.append('Friday'); print(f"Appended at right: {dq}")
dq.appendleft("Sunday"); print(f"Appended at left: {dq}")
dq.pop(); print(f"Deleting from right: {dq}")
dq.popleft(); print(f"Deleting from left: {dq}")
```

    Double ended queue: deque(['Monday', 'Tuesday', 'Wesday', 'Thursday'])
    Appended at right: deque(['Monday', 'Tuesday', 'Wesday', 'Thursday', 'Friday'])
    Appended at left: deque(['Sunday', 'Monday', 'Tuesday', 'Wesday', 'Thursday', 'Friday'])
    Deleting from right: deque(['Sunday', 'Monday', 'Tuesday', 'Wesday', 'Thursday'])
    Deleting from left: deque(['Monday', 'Tuesday', 'Wesday', 'Thursday'])

# 二叉树

1）定义：二叉树是每个结点最多有两个子树的树结构。它有五种基本形态：二叉树可以是空集；根可以有空的左子树或右子树；或者左、右子树皆为空
2）特点：
   1. 性质1：二叉树第i层上的结点数目最多为$2^{i-1}$(i>=1)；
   2. 性质2：深度为k的二叉树至多有$2^{k-1}$个结点（k>=1）；
   3. 性质3：包含n个结点的二叉树的高度至少为$log_{2} n+1$；
   4. 性质4：在任意一棵二叉树中，若终端结点的个数为$n_0$，度为2的结点数为$n_2$，则$n_0=n_2+1$

```python
class TreeNode(object):
    def __init__(self, item):
        self.item = item
        self.left_child = None
        self.right_child = None
```

```python
class Tree(object):
    def __init__(self):
        self.root = None

    def add(self, item):
        node = TreeNode(item)
        if self.root is None:
            self.root = node
        else:
            q = [self.root]
            while True:
                pop_node = q.pop(0)
                if pop_node.left_child is None:
                    pop_node.left_child = node
                    break
                elif pop_node.right_child is None:
                    pop_node.right_child = node
                    break
                else:
                    q.append(pop_node.left_child)
                    q.append(pop_node.right_child)

    def traverse(self):
        if self.root is None:
            return None

        q = [self.root]

        res = [self.root.item]

        while q != []:
            pop_node = q.pop(0)

            if pop_node.left_child is not None:
                q.append(pop_node.left_child)
                res.append(pop_node.left_child.item)

            if pop_node.right_child is not None:
                q.append(pop_node.right_child)
                res.append(pop_node.right_child.item)

        return res

    def traverse_preorder(self, root, res=None):  # 先序遍历
        if res is None: res = []

        def preorder(root, res):
            if root is None: return None
            res.append(root.item)
            preorder(root.left_child, res)
            preorder(root.right_child, res)

        preorder(root, res)
        return res

    def traverse_inorder(self, root, res=None):  # 中序序遍历
        if res is None: res = []

        def inorder(root, res):
            if root is None: return None
            inorder(root.left_child, res)
            res.append(root.item)
            inorder(root.right_child, res)

        inorder(root, res)
        return res

    def traverse_postorder(self, root, res=None):  # 中序序遍历
        if res is None: res = []

        def postorder(root, res):
            if root is None: return None
            postorder(root.left_child, res)
            postorder(root.right_child, res)
            res.append(root.item)

        postorder(root, res)
        return res
```

```python
t = Tree()
for i in range(10):
    t.add(i)
```

```python
# 层序遍历
print(t.traverse())
print(t.traverse_preorder(t.root))
print(t.traverse_inorder(t.root))
print(t.traverse_postorder(t.root))
```

    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    [0, 1, 3, 7, 8, 4, 9, 2, 5, 6]
    [7, 3, 8, 1, 9, 4, 0, 5, 2, 6]
    [7, 8, 3, 9, 4, 1, 5, 6, 2, 0]

# Container datatypes --- collections

## Counter

A Counter is a dict subclass for counting hashable objects. It is a collection where elements are stored as dictionary keys and their counts are stored as dictionary values. Counts are allowed to be any integer value including zero or negative counts. The Counter class is similar to bags or multisets in other languages.

```python
from collections import Counter

# 1. initial to take a count in two ways:
cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
    cnt[word] += 1
print(f"after count: {cnt}")
print(f"Counting directly from array: {Counter(['red', 'blue', 'red', 'green', 'blue', 'blue'])}")
```

    after count: Counter({'blue': 3, 'red': 2, 'green': 1})
    Counting directly from array: Counter({'blue': 3, 'red': 2, 'green': 1})

```python
# More examples from
print(f"a new, empty counter {Counter()}")
print(f"a new counter from an iterable {Counter('gallahad') }")
print(f"a new counter from a mapping {Counter({'red': 4, 'blue': 2})}")
print(f"a new counter from keyword args {Counter(cats=4, dogs=8) }")
```

    a new, empty counter Counter()
    a new counter from an iterable Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})
    a new counter from a mapping Counter({'red': 4, 'blue': 2})
    a new counter from keyword args Counter({'dogs': 8, 'cats': 4})

```python
# Useful APIs
c = Counter(a=4, b=2, c=0, d=-2)
print(c)
print(f"elements: {list(c.elements())}")

```

    Counter({'a': 4, 'b': 2, 'c': 0, 'd': -2})
    elements: ['a', 'a', 'a', 'a', 'b', 'b']

```python
#
c = Counter('abracadabra')

top3 = c.most_common(3)
n = 2
least_n = c.most_common()[:-n-1:-1] # n least common elements
print(f"Original Count: {c}")
print(f"Top 3 most common: {top3}")
print(f"N least common elements: {least_n}")
```

    Original Count: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
    Top 3 most common: [('a', 5), ('b', 2), ('r', 2)]
    N least common elements: [('d', 1), ('c', 1)]

# Heap

A heap is a binary tree inside an array. A heap is sorted based on the "heap property" that determines the order of the nodes in the tree.

\begin{definition}[Heap]
Suppose that $arr = [k_0, k_1, k_2, \ldots, k_{n-1}]$, $\forall i \in [0, \frac{n - 2}{2}]$
\begin{itemize}
\item \textbf{Max-Heap}
 \begin{equation}
    \begin{cases}
      k_i \geq k_{2i + 1} \\
      k_i \geq k_{2i + 2}
    \end{cases}
  \end{equation}
\item \textbf{Min-Heap}
\begin{equation}
    \begin{cases}
      k_i \leq k_{2i + 1} \\
      k_i \leq k_{2i + 2}
    \end{cases}
  \end{equation}
\end{itemize}
\end{definition}

If $i$ is the index of a node, then the following formulas give the array indices of its parent and child nodes:
\begin{aligned}
parent(i) &= floor(\frac{i - 1}{2}) \\
left(i)   &= 2i + 1 \\
right(i)  &= left(i) + 1 = 2i + 2 \\
\end{aligned}
The left and right nodes are always stored right next to each other.

## Heap Property

```python
# 1. Using Max- or Min-heap property to verify that if an array is a heap.
arr = [ 10, 7, 2, 5, 1 ]
import math

def parent(index):
    return math.floor((index - 1) / 2)

def left(index):
    return 2*index + 1

def right(index):
    return 2*index + 2

hold_props = [arr[parent(i)] >= arr[i] for i in range(1, len(arr))]
print(hold_props)
```

    [True, True, True, True]

- In Max-heap, all parent nodes is bigger or equal than their children nodes, so the largest item at the root of the tree.
- In Min-heap, all parent nodes is smaller or equal than their children nodes, so the smallest item at the root of the tree.
- The root of the heap has the maximum or minimum element, but the sort order of other elements are not predictable.

## Heap vs Regular Tree (Binary search tree)

- **Order of the nodes.** In a Binary search tree (BST), the left child must be smaller than its parent, and the right child must be greater. This is not true for a heap. In a max-heap both children must be smaller than the parent, while in a min-heap they both must be greater.
- **Memory.** Traditional trees take up more memory than just the data they store. You need to allocate additional storage for the node objects and pointers to the left/right child nodes. A heap only uses a plain array for storage and uses no pointers.
- **Balancing.** A binary search tree must be "balanced" so that most operations have O(log n) performance. You can either insert and delete your data in a random order or use something like an AVL tree or red-black tree, but with heaps we don't actually need the entire tree to be sorted. We just want the heap property to be fulfilled, so balancing isn't an issue. Because of the way the heap is structured, heaps can guarantee O(log n) performance.
- **Searching.** Whereas searching is fast in a binary tree, it is slow in a heap. Searching isn't a top priority in a heap since the purpose of a heap is to put the largest (or smallest) node at the front and to allow relatively fast inserts and deletes.

```python
import math

class Heap:
    def __init__(self):

        self.data = []

    @property
    def size(self):
        return len(self.data)

    def insert(self, value):
        """
        Adds the new element to the end of the heap
        and then uses shiftUp() to fix the heap.
        """
        self.data.append(value)
        self.shiftUp(self.size - 1)

    def remove(self):
        """
        Removes and returns the maximum value (max-heap) or
        the minimum value (min-heap). To fill up the hole left
        by removing the element, the very last element is moved
        to the root position and then shiftDown() fixes up the heap.
        (This is sometimes called "extract min" or "extract max".)
        """
        pass

    def removeAtIndex(self, index):
        """
        Just like remove() with the exception that it allows you to
        remove any item from the heap, not just the root. This calls
        both shiftDown(), in case the new element is out-of-order with
        its children, and shiftUp(), in case the element is out-of-order
        with its parents.
        """
        pass

    def replace(self, index, value):
        """
        Assigns a smaller (min-heap) or larger (max-heap) value to a node.
        Because this invalidates the heap property, it uses shiftUp() to
        patch things up. (Also called "decrease key" and "increase key".)
        """
        pass

    def search(self, value):
        """
        Heaps are not built for efficient searches, but the replace() and
        removeAtIndex() operations require the array index of the node,
        so you need to find that index. Time: O(n).
        """
        pass

    def buildHeap(self, array):
        """
        Converts an (unsorted) array into a heap by repeatedly calling insert().
        If you are smart about this, it can be done in O(n) time.
        """
        pass

    def peek(self):
        """
        The heap also has a peek() function that returns the maximum (max-heap)
        or minimum (min-heap) element, without removing it from the heap.
        Time: O(1).
        """
        return self.data[0] if self.size() > 0 else None

    def shiftUp(self, index):
        """
        If the element is greater (max-heap) or smaller (min-heap)
        than its parent, it needs to be swapped with the parent.
        This makes it move up the tree.

        Shifting up or down is a recursive procedure that takes O(log n) time.
        """
        parent_index = self.parent(index)
        while index > 1 and self.data[parent_index] > self.data[index]:
            self.data[parent_index], self.data[index] = self.data[index], self.data[parent_index]
            index = parent_index
            parent_index = self.parent(index)

    def shiftDown(self, index):
        """
        If the element is smaller (max-heap) or greater (min-heap)
        than its children, it needs to move down the tree.
        This operation is also called "heapify".

        Shifting up or down is a recursive procedure that takes O(log n) time.
        """
        pass

    def heapify(self):
        pass

    @staticmethod
    def parent(index):
        return math.floor((index - 1) / 2)

    @staticmethod
    def left(index):
        return 2 * index + 1

    @staticmethod
    def right(index):
        return 2 * index + 2

if __name__ == "__main__":
    pass
```

## Heap queue algorithm in Python

This module provides an implementation of the heap queue algorithm, also known as the priority queue algorithm.

```python
import heapq
# 1. Creat a heap

h1 = []
data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]

heapq.heapify(data) # Transform list x into a heap, in-place, in linear time.
print(data)
```

    [0, 1, 2, 6, 3, 5, 4, 7, 8, 9]

```python
# Push the value item onto the heap, maintaining the heap invariant.
heapq.heappush(data, 3)
print(data)
```

    [0, 1, 2, 6, 3, 5, 4, 7, 8, 9, 3]

```python
# Pop and return the smallest item from the heap, maintaining the heap
# invariant. If the heap is empty, IndexError is raised. To access the
# smallest item without popping it, use heap[0].

result = heapq.heappop(data)
print(data)
print(result)
```

    [1, 3, 2, 6, 3, 5, 4, 7, 8, 9]
    0

```python
def heapsort(iterable):
    h = []

    # build a min-heap
    for value in iterable:
        heapq.heappush(h, value)

    return [heapq.heappop(h) for _ in range(len(iterable))]
```

```python
heapsort([1, 3, 2, 6, 3, 5, 4, 7, 8, 9])
```

    [1, 2, 3, 3, 4, 5, 6, 7, 8, 9]

# Reference

1. [Python 中常见的数据结构](https://zhuanlan.zhihu.com/p/69487899)
2. [Python对数据结构的实现](https://blog.csdn.net/mxz19901102/article/details/80071864?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control)
3. [常见的数据结构](https://zhuanlan.zhihu.com/p/93928546)
4. [Heap](https://github.com/raywenderlich/swift-algorithm-club/tree/master/Heap)

```python

```