```python
# %load ../../preconfig.py
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(color_codes=True)
plt.rcParams['axes.grid'] = False

#import numpy as np
#import pandas as pd

#import sklearn

#import itertools

import logging
logger = logging.getLogger()

def show_image(filename, figsize=None, res_dir=True):
    if figsize:
        plt.figure(figsize=figsize)

    if res_dir:
        filename = './res/{}'.format(filename)

    plt.imshow(plt.imread(filename))

```

26 Maximum Flow
================

each directed edge in a flow network like a conduit for the material: Each conduit has a stated capacity, vertices are conduit junctions.

In the maximum-flow problem, we wish to compute the greatest rate at which we can ship material from the source to the sink without violating any capacity constraints.

### 26.1 Flow networks
Let $G = (V, E)$ be a flow network with a capacity function $c$.

Let $s$ be the source of the network, and let $t$ be the sink.

A **flow** in $G$ is a real-valued function $f : V \times V \to \mathcal{R}$ that satisfies the following two properties:

+ **Capacity constraint**: $0 \geq f(u, v) \geq c(u, v) : \forall u, v \in V$

+ **Flow conservation**: $$\displaystyle \sum_{v \in V} f(v, u) = \sum_{v \in V} f(u, v)$$

1. real-world flow problem may violates our assumption:
modeling problems with antiparalled edges.

2. networks with multiple sources and sinks:
add a **supersourse** and a **supersink**.

```python
plt.imshow(plt.imread('./res/fig26_1.png'))
```

```python
# Exercise
```

### 26.2 The Ford-Fulkerson method
The Ford-Fulkerson method depends on three important ideas: residual networks, augmenting paths, and cuts.

```c
FORD-FULKERSON-METHOD(G, s, t)
initialize flow f to 0

while there exists an augmenting path p in the residual network G_f
    augment flow f along p

return f
```

#### Residual networks
the residual network $G_f$ consists of edges with capacitites that represent how we can change the flow on edges of $G$.

we define the **residual capacity** $c_f(u, v)$ by
\begin{equation}
    c_f(u, v) = \begin{cases}
        c(u, v) - f(u, v) \, & \text{ if } (u, v) \in E \\
        f(v, u) \, & \text{ if } (v, u) \in E \\
        0 \, & \text{ otherwise}
    \end{cases}
\end{equation}

the **residual network** of $G$ induced by $f$ is $G_f = (V, E_f)$, where
$$E_f = \{ (u, v) \in V \times V : c_f(u, v) > 0 \}$$

If $f$ is a flow in $G$ and $f'$ is a flow in the corresponding residual network $G_f$, we define$f \uparrow f'$, the **augmentation** of flow $f$ by $f'$:
\begin{equation}
    (f \uparrow f')(u, v) = \begin{cases}
        f(u, v) + f'(u, v) - f'(v, u) \, & \text{ if } (u, v) \in E \\
        0 \, & \text{ otherwise}
    \end{cases}
\end{equation}

```python
show_image('fig26_4.png', figsize=(8,12))
```

#### Augmenting paths
an **augmenting path** $p$ is a simple path from $s$ to $t$ in the residual network $G_f$.

$$c_f(p) = \min \{ c_f(u, v): \text{ $(u, v)$ is on $p$} \}$$

#### Cuts of flow networks
The Ford-Fulkerson method repeatedly augments the flow along augmenting paths until it has found a maximum flow.

The max-flow min-cut theorem tells us that a flow is maximum if and only if its residual network contains no augmenting path.

#### The basic Ford-Fulkerson algorithm

```python
show_image('ford.png')
```

```python
show_image('fig26_6.png')
```

#### The Edmonds-Karp algorithm
We can improve the boudn of FORD-FULKERSON by finding the augmenting path $p$ in line 3 with a breadth-first search.

```python
#Exercise
```

### 26.3 Maximum bipartite matching
a maximum matching in a bipartite graph $G$ corresponds to a maximum flow in its corresponding flow network $G'$, and we can therefore compute a maximum matching in $G$ by running a maximum-flow algorithm on $G'$.

```python
show_image('fig26_8.png')
```

```python
#Exercise
```

### 26.4 Push-relabel algorithms


# Agents: Lab 2

```python
from IPython.core.display import HTML
css_file = 'https://raw.githubusercontent.com/ngcm/training-public/master/ipython_notebook_styles/ngcmstyle.css'
HTML(url=css_file)
```

<link href='http://fonts.googleapis.com/css?family=Open+Sans:100,300,400,500,700,800,900,100italic,300italic,400italic,500italic,700italic,800italic,900italic' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Arvo:400,700,400italic' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=PT+Mono' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Shadows+Into+Light' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Nixie+One' rel='stylesheet' type='text/css'>
<style>

@font-face {
    font-family: "Computer Modern";
    src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');
}

#notebook_panel { /* main background */
    background: rgb(245,245,245);
}

div.cell { /* set cell width */
    width: 1000px;
}

div #notebook { /* centre the content */
    background: #fff; /* white background for content */
    width: 1200px;
    margin: auto;
    padding-left: 0em;
}

#notebook li { /* More space between bullet points */
margin-top:0.8em;
}

/* draw border around running cells */
div.cell.border-box-sizing.code_cell.running {
    border: 1px solid #111;
}

/* Put a solid color box around each cell and its output, visually linking them*/
div.cell.code_cell {
    background-color: rgb(256,256,256);
    border-radius: 0px;
    padding: 0.5em;
    margin-left:1em;
    margin-top: 1em;
}

div.text_cell_render{
    font-family: 'Open Sans' sans-serif;
    line-height: 140%;
    font-size: 125%;
    font-weight: 400;
    width:900px;
    margin-left:auto;
    margin-right:auto;
}

/* Formatting for header cells */
.text_cell_render h1 {
    font-family: 'Arvo', serif;
    font-style:regular;
    font-weight: 400;
    font-size: 45pt;
    line-height: 100%;
    color: rgb(0,51,102);
    margin-bottom: 0.5em;
    margin-top: 0.5em;
    display: block;
}
.text_cell_render h2 {
    font-family: 'Arvo', serif;
    font-weight: 400;
    font-size: 30pt;
    line-height: 100%;
    color: rgb(0,51,102);
    margin-bottom: 0.1em;
    margin-top: 0.3em;
    display: block;
}

.text_cell_render h3 {
    font-family: 'Arvo', serif;
    margin-top:16px;
	font-size: 22pt;
    font-weight: 600;
    margin-bottom: 3px;
    font-style: regular;
    color: rgb(102,102,0);
}

.text_cell_render h4 {    /*Use this for captions*/
    font-family: 'Arvo', serif;
    font-size: 14pt;
    text-align: center;
    margin-top: 0em;
    margin-bottom: 2em;
    font-style: regular;
}

.text_cell_render h5 {  /*Use this for small titles*/
    font-family: 'Arvo', sans-serif;
    font-weight: 400;
    font-size: 16pt;
    color: rgb(163,0,0);
    font-style: italic;
    margin-bottom: .1em;
    margin-top: 0.8em;
    display: block;
}

.text_cell_render h6 { /*use this for copyright note*/
    font-family: 'PT Mono', sans-serif;
    font-weight: 300;
    font-size: 9pt;
    line-height: 100%;
    color: grey;
    margin-bottom: 1px;
    margin-top: 1px;
}

.CodeMirror{
        font-family: "PT Mono";
        font-size: 90%;
}

</style>

## Flocking behaviour

Agents should both interact with their environment and each other, and change their behaviour to reach some goal (often by maximizing a utility function or similar). One example is a simple model of the behaviour of groups of birds (flocking) or fish (schooling). This *CSA* model says that all individuals only change direction in order to improve

* **Cohesion**: they steer towards the local average location of their flockmates;
* **Separation**: they steer to avoid crowding local flockmates;
* **Alignment**: they steer towards the average heading of their local flockmates.

Here we investigate how this model looks, depending on the initial velocity of the individuals.

```python
%matplotlib inline
import math
import numpy
from matplotlib import pyplot, animation

from matplotlib import rcParams
rcParams['font.family'] = 'serif'
rcParams['font.size'] = 16
rcParams['figure.figsize'] = (12,6)

import scipy
from scipy.optimize import minimize

from __future__ import division
```

Define a class called `Agent`. This should store the 2-dimensional ${\bf z} = (x, y)$ location of the individual, and its 2-dimensional velocity ${\bf v} = (v_x, v_y)$. It should have a method that updates its location over a timestep $\Delta t$ as

\begin{equation}
  {\bf z} = \begin{pmatrix} x \\ y \end{pmatrix} \to \begin{pmatrix} x \\ y \end{pmatrix} + \Delta t \begin{pmatrix} v_x \\ v_y \end{pmatrix} = {\bf z} + \Delta t \, {\bf v}.
\end{equation}

The `Agent` should also have a method that changes its velocity to maximize its "CSA utility": given a list of other agents that are the "local flockmates", it should choose its heading to maximize cohesion, separation and alignment. The CSA utility is a function of the locations and velocities that returns a single number, and is to be maximized by varying the direction of the velocity of this `Agent`.

As an example, define the following utility function:

\begin{equation}
  f \left( {\bf v} ; {\bf z}, {\bf z}_i, {\bf v}_i \right) = C \frac{{\bf v} \cdot \Delta {\bf z}}{ \| {\bf v} \| \| \Delta {\bf z} \| } + A \frac{{\bf v} \cdot {\bf V}}{ \| {\bf v} \| \| {\bf V} \| } - S \frac{{\bf v} \cdot \Delta {\bf z}_{\text{min}}}{ \| {\bf v} \| \| \Delta {\bf z}_{\text{min}} \|^3 }.
\end{equation}

$f$ is the utility function itself. It depends on the velocity ${\bf v}$ of the current `Agent`, which can be varied. It also depends on the location ${\bf z}$ of the current `Agent`, as well as the locations ${\bf z}_i$ and velocities ${\bf v}_i$ of the local flockmates, which cannot be varied.

The coefficients $C, S, A$ give the relative importance of improving the cohesion, separation, and alignment respectively.

$\Delta {\bf z}$ is the *average location difference* between the current `Agent` position ${\bf z}$ and the position of its local flockmates ${\bf z}_i$, given by

\begin{equation}
  \Delta {\bf z} = \frac{1}{N} \sum_{i=1}^{N} \begin{pmatrix} x_i - x \\ y_i - y \end{pmatrix}
\end{equation}

${\bf V}$ is the *average velocity* of the local flockmates, given by

\begin{equation}
  {\bf V} = \frac{1}{N} \sum_{i=1}^{N} \begin{pmatrix} (v_x)_i \\ (v_y)_i \end{pmatrix}.
\end{equation}

$\Delta {\bf z}_{\text{min}}$ is the location of the flockmate that is closest to the current `Agent`. Note that the norm of this difference in the denominator is cubed, to ensure that when two agents get close together they are strongly repelled.

**Note**: it is only the *direction* of the velocity ${\bf v}$ that matters in this function. We can define a set of magnitudes and angles:

\begin{align}
  {\bf v} &= v \left( \cos(\theta) \hat{\bf i} + \sin(\theta) \hat{\bf j} \right), \\
  \Delta {\bf z} &= \Delta z \left( \cos(\theta_z) \hat{\bf i} + \cos(\theta_z) \hat{\bf j} \right), \\
  {\bf V} &= V \left( \cos(\theta_V) \hat{\bf i} + \cos(\theta_V) \hat{\bf j} \right), \\
  \Delta {\bf z}_{\text{min}} &= \Delta z_{\text{min}} \left( \cos(\theta_{z_{\text{min}}}) \hat{\bf i} + \cos(\theta_{z_{\text{min}}}) \hat{\bf j} \right).
\end{align}

We can then write

\begin{equation}
  f \left( \theta ; {\bf z}, {\bf z}_i, {\bf v}_i \right) = C \cos(\theta - \theta_z) + A \cos(\theta - \theta_V) - S \frac{\cos(\theta - \theta_{z_{\text{min}}})}{\Delta z_{\text{min}}^2 }.
\end{equation}

To start, use values for the parameters of

\begin{align}
  C &= 1, \\ A &=5, \\ S &= 0.1.
\end{align}

```python
class Agent(object):

    def __init__(self, location, velocity, C=1, A=5, S=0.1):
        # Complete this

    def step(self, dt):
        # And this

    def steer(self, neighbours):
        # And this
```

Test that the `Agent` steers as expected given a list of zero or one local flockmates.

```python

```

Now define a `Flock` class containing a list of `Agents`. The flock should be initialized from appropriate `numpy` arrays and values for the locality radius $r_l$, which should default to `1`. The flock should be able to compute and return

* the positions of all its members
* the average location of all its members
* the average velocity, or heading, of all its members
* the average distance from the average location.

Test, with flocks of one, two, and three agents, that it behaves as you expect. Timesteps of order $0.1$ for velocities of order $1$ are reasonable.

```python
class Flock(object):
    def __init__(self, locations, velocities, rl=1):
        # Complete this

    def step(self, dt):
        # And this

    def locations(self):
        # And this

    def velocities(self):
        # And this

    def average_location(self):
        # And this

    def average_velocity(self):
        # And this

    def average_width(self):
        # And this
```

```python

```

Create a flock of $50$ agents randomly distributed within $[0, 5]^2$. Give them initial velocities of $(1, 1) + 10^{-2} {\bf v}_r$, where ${\bf v}_r$ is a random velocity with each component a uniform random number in $[0, 1]$.

Evolve the flock using timesteps of $0.05$ for $200$ steps and plot the flock behaviour. Also plot the "width" of the flock (the average distance from the average location), and the average location and heading with time.

```python

```

FEEG6016 Simulation and Modelling/06-Agents-Lab-2.ipynb