In this chapter we will look at a simple graph problem and see how to solve it so that we are using close to 100% of the theoretical maximum performance of the computer.

We will use the following simple graph problem as our running example throughout this chapter. We have a directed graph with $n$ nodes. The nodes of the graph are labeled with numbers $0,1,\dotsc,n-1$. There is a directed edge between each pair of the nodes; the **cost** of the edge between nodes $i$ and $j$ is $d_{ij}$; we will assume that $d_{ij}$ is a nonnegative real number. For convenience, we write $d_{ii} = 0$ for each node $i$.

However, the costs do not necessarily satisfy the triangle inequality. We might have an edge of cost $d_{ij} = 10$ from node $i$ to $j$, but there might be an intermediate node $k$ with $d_{ik} = 2$ and $d_{kj} = 3$. Then we can follow the route $i \to k \to j$ at a total cost of $2+3 = 5$, while the direct route $i \to j$ would cost $10$.

Our task is to find for all $i$ and $j$ what is the cost of getting from $i$ to $j$ by taking **at most two edges**. If we write $r_{ij}$ for the result, then clearly
$$
r_{ij} = \min_k (d_{ik} + d_{kj}),
$$
where $k$ ranges over $0,1,\dotsc,n-1$. Note that we will also consider here e.g. the route $i \to i \to j$, and hence we will also find a path of one edge if it happens to be cheapest.

We can write the distances $d_{ij}$ as a matrix $D$, and the results $r_{ij}$ as a matrix $R$. Then $R = D \circ D$, where $\circ$ denotes min-plus matrix multiplication.

If we iterate the process and calculate
$$
D_2 = D \circ D, \quad D_4 = D_2 \circ D_2, \quad D_8 = D_4 \circ D_4, \quad \dotsc
$$
we can quickly find the cost of getting from any node to any other node by following at most $2, 4, 8, \dotsc$ edges. Iterating this operation for a logarithmic number of times would therefore also give *all-pairs shortest path distances* (but recall that there are more direct ways of solving the all-pairs shortest path problem).

We will implement a C++ function `step`

with the following prototype:

```
void step(float* r, const float* d, int n);
```

Here `n`

denotes the number of nodes, `d`

contains the input, and `r`

will contain the result. Both `d`

and `r`

are pointers to arrays with `n * n`

floats.

The cost of the edge from node `i`

to node `j`

is stored in `d[n*i + j]`

. Similarly, the cost of getting from `i`

to `j`

by following at most two edges will be stored in `r[n*i + j]`

. Here `0 <= i < n`

and `0 <= j < n`

.

Here is a simple example of how we could call `step`

:

```
int main() {
constexpr int n = 3;
const float d[n*n] = {
0, 8, 2,
1, 0, 9,
4, 5, 0,
};
float r[n*n];
step(r, d, n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
std::cout << r[i*n + j] << " ";
}
std::cout << "\n";
}
}
```

This program should produce the following output:

0 7 2 1 0 3 4 5 0

Here, for example, there is a direct edge from node 0 to node 1 with cost 8. However, we can take an edge from node 0 to node 2 (cost 2), and then an edge from node 2 to node 1 (cost 5), which results in a path of total cost 7.