Recording Which Things Are Connected
A table of pump readings leaves out the pipes between pumps. A graph records those relationships so calculations can use the connections.
13 sections · 4 questions · 2 coding challenges
The arrow keys move between sections too.
Using Relationships Alongside Measurements
BOTIE
Before reaching a learned graph model, we need an unambiguous representation. Our pipe network is an invented example, and an edge records a connection rather than proving a causal effect.
Sources for this history
Could a Problem in One Pump Affect Another?
Botie has a reading for each pump, but a pump’s behaviour can depend on what reaches it through the pipe network. Independent rows do not describe that network.
A graph adds two fundamental pieces: nodes for the things and edges for the relationships. We will turn a small network into an adjacency matrix and check exactly what each row means.
The binary network is an invented arrangement of pump connections.
Step 1 of 4
Name the nodes
Keep one stable ordering.
Nodes and properties (3)
- 0: intake
- 1: pump
- 2: outlet
- No relationships in this result.
Step 2 of 4
Record edges
This first network is undirected.
Nodes and properties (3)
- 0: intake
- 1: pump
- 2: outlet
- 0: intake connected to 1: pump
- 1: pump connected to 2: outlet
Step 3 of 4
Store neighbours by row
A one marks a connection to the column node.
| Connected from | 0: intake | 1: pump | 2: outlet |
|---|---|---|---|
| Adjacency row 0 | 0 | 1 | 0 |
| Adjacency row 1 | 1 | 0 | 1 |
| Adjacency row 2 | 0 | 1 | 0 |
Adjacency row 0
- 0: intake
- 0
- 1: pump
- 1
- 2: outlet
- 0
Adjacency row 1
- 0: intake
- 1
- 1: pump
- 0
- 2: outlet
- 1
Adjacency row 2
- 0: intake
- 0
- 1: pump
- 1
- 2: outlet
- 0
Step 4 of 4
A pump can exist without having a connection
The isolated pump still needs a row and a column. Its degree is zero, but deleting its row would remove the pump itself and shift the identities of the remaining entries.
Nodes and properties (4)
- Pump A
- Pump B
- Pump C
- Pump D · Degree 0
- Pump A connected to Pump B
- Pump B connected to Pump C
Rows and columns keep node identities attached to connections
Each row retains its node identity while its edge entries are counted.
Which pumps have the most direct connections?
Choose a pump row and count its neighbours. When changing an undirected connection, change the matching entry on the other side of the matrix as well.
BOTIE
Degree of each pump
- 01
- 12
- 21
Follow the operations
1. Undirected binary adjacency matrix
0 1 0 1 0 1 0 1 0 2. Add each row
- 01
- 12
- 21
3. Result
- 01
- 12
- 21
For weighted graphs, row sums measure total weight instead of neighbour count.
1. Separate Node Features From Edges
We need two tables for different jobs. The feature matrix gives one row of measurements per node. The adjacency matrix records which nodes are connected, using that same node order for its rows and columns.
An undirected connection appears in both directions. For a directed edge, we need an agreed orientation. Here the row names the source and the column names the destination. That convention will determine which matrix multiplication sends information the way we intend.
Changing node order requires changing both adjacency axes and feature rows together.
2. Calculate Degree Without Guessing
For an unweighted graph without self-loops, row sums count outgoing neighbours. In an undirected graph they give degree. For weighted edges the same sum is total edge weight, which need not equal neighbour count.
A = [[0,1,0], [1,0,1], [0,1,0]]
Row sums = [1,2,1]A node with no edges still exists and still needs a feature row.
3. Choose a Storage Structure
A dense adjacency matrix makes a small network easy to inspect but uses space for every possible pair. An edge list stores only existing edges as source-destination pairs. Sparse matrices support many of the same algebraic operations without storing every zero.
Duplicate entries require a policy. Counting the same physical pipe twice may accidentally double its influence when building a weighted matrix.
The NumPy exercises use dense arrays for clarity, not as a recommendation for large networks.
Read the neighbours of one pump from its row
This pump has a position for every possible neighbour, including itself. A one means an edge is present and the zero on its own position means no self-loop.
import numpy as np
pump_row = np.array([0, 1, 1, 1])
print(np.flatnonzero(pump_row).tolist())
print(int(pump_row.sum()))[1, 2, 3]
3The neighbour indices identify three connections. Practice counts degrees across a complete adjacency matrix and checks the undirected symmetry.
4. Define What a Connection Permits
A physical pipe, a friendship, a citation, and a similarity edge imply different things. Decide whether messages may travel with or against a directed edge and whether edge weights express capacity, affinity, or another quantity.
A connection alone does not establish causation. Later learning can use relationships predictively even when their causal interpretation is unknown.
Botie’s workshop first checks degrees before any information is passed through the network.
5. A Pipe Connection Has a Direction Only If the Problem Gives It One
An undirected edge says two pumps are connected. A directed edge can instead describe permitted flow from one pump to another. Decide which relation the model needs before filling an adjacency matrix.
State whether rows identify senders or receivers. Matrix multiplication does not infer this convention. With sender rows, multiplying a row-vector distribution on the right moves mass along outgoing edges; gathering incoming node features uses the transposed adjacency.
6. Keep Node Identity When Converting an Edge List
An edge list stores endpoint indices instead of a dense table full of zeros. The indices must refer to a saved node vocabulary. Reordering a feature table without reindexing the edges sends messages to the wrong pumps.
Repeated edges need a policy: accumulate their weights for a multigraph or deduplicate them for a simple graph. Do not let the storage conversion choose that meaning accidentally.
Accumulate two reports of the same directed connection
Rows are source nodes and columns are destination nodes. Each report has unit weight.
import numpy as np
source = np.array([0,0,1])
target = np.array([1,1,2])
A = np.zeros((3,3), dtype=int)
np.add.at(A, (source,target), 1)
print(A.tolist())
print(A.sum(axis=1).tolist())[[0, 2, 0], [0, 0, 1], [0, 0, 0]]
[2, 1, 0]Node zero has two reported edges to node one under the accumulation policy. A simple-graph interpretation would convert that count to one.
7. An Isolated Node Still Has Features
A node with no edges should not disappear merely because an edge list never mentions it. Store the full node vocabulary independently. Its features can still support a node-level prediction or a later connection.
For a large sparse network, avoid constructing a dense square matrix solely for convenience. The edge list or a sparse matrix can express the same connectivity with storage proportional to observed edges. Keep the tiny dense version as an inspectable teaching case.
Check yourself
Questions on Parts 1 to 7
Question 1 of 4
Which node has two neighbours?
Use the information below.
A=[[0,1,0],[1,0,1],[0,1,0]].Try it with Botie
Build with Botie
Write and run Python