Graphs and trees: the structure that both search and neural networks stand on
Vertices and edges, degrees, the adjacency matrix, paths and components, BFS and Dijkstra, trees, the minimum spanning tree and the computation graph of a neuron — all on one graph with seven cities.
Series AI basics Part 8 of 52
- Map of artificial intelligence: what is what and how it all fits together
- A brief history of artificial intelligence: from Turing to language models
- Data, model, training, inference: the basic terms on a single example
- How to read mathematical notation: symbols, indices, sums and quantifiers
- Sets and relations: the building blocks of definitions in AI
- Functions and mappings: why every AI model is a function
- Logic and proofs: the rules AI reasons by
- Graphs and trees: the structure that both search and neural networks stand on
- Linear algebra for machine learning: vectors, matrices and why AI mostly multiplies
- Derivatives, the gradient and the chain rule: how a model finds out which way to learn
- Gradient descent: how a model learns
- What probability is: from rolling dice to the Kolmogorov axioms
- Conditional probability and Bayes’ theorem: how to update your estimate when you learn something new
- Random variables and the cumulative distribution function: one function that tells you everything about a distribution
- Probability density and probability mass functions: why a continuous variable has zero probability at a point
- Expected value, variance and covariance: where a distribution lies, how wide it is and what goes with what
- Overview of probability distributions: Bernoulli, binomial, Poisson, uniform, normal and exponential
- Law of large numbers and central limit theorem: why averages behave so predictably
- Statistics and parameter estimation: maximum likelihood, MAP and confidence intervals
- Information theory: entropy, cross-entropy and KL divergence — where loss functions come from
- State-space search: BFS, DFS, UCS and A* with animations
- Games and adversaries: minimax, alpha-beta pruning and Monte Carlo tree search
- Constraint satisfaction: backtracking, constraint propagation and AC-3 on sudoku and a map of Czech regions
- Logic and knowledge systems: forward and backward chaining, resolution and expert systems
- Planning: STRIPS, the blocks world, heuristics from relaxation and planning in AI agents
- Local search and simulated annealing: a travelling salesman through the Czech regional capitals
- Genetic algorithms: population, crossover, mutation and selection on a backpack for a hike
- Evolution strategies and genetic programming: from the one-fifth rule to Kepler’s law
- Ant colony optimization: how a pheromone trail finds a short path
- Particle swarm optimisation: inertia, personal experience and the swarm’s experience
- Neuroevolution: evolving the weights and shape of neural networks, and the NEAT algorithm
- Fuzzy sets and membership functions: how to write down “somewhat warm”
- Fuzzy logic and probability: why “somewhat warm” does not mean “probably warm”
- Fuzzy logic: t-norms, implications and IF–THEN rules
- Fuzzy control: Mamdani and Sugeno from a fan to a pole on a cart
- Fuzzy clustering: the fuzzy c-means algorithm and points between clusters
- Neuro-fuzzy systems (ANFIS): fuzzy rules that learn from data
- Markov chains: the transition matrix, the stationary distribution and PageRank
- Hidden Markov models: the Viterbi algorithm and the dishonest casino
- Bayesian networks: why the grass is wet and what it means for the sprinkler
- The Kalman filter: how to estimate where a car is and how fast it goes from imprecise measurements
- Types of machine learning: supervised, unsupervised, semi-supervised and more
- Prompts, context and RAG: how to give a model the right information
- Variational autoencoders (VAE): new images from a continuous latent space
- Generative adversarial networks (GAN): the forger versus the detective
- Diffusion models: how pure noise becomes an image
- Markov decision processes: states, actions, rewards and the Bellman equations
- Q-learning and DQN: learning the value of actions, from a table to a neural network
- Policy gradient and PPO: learning the policy directly
- How an AI agent works: a language model in a loop with tools
- Programming with AI agents: the task, tests and review
- Evaluating and securing AI systems: how to measure and how to keep watch
Full series syllabus 52 of 83 topics published
- What a graph, degree and connectedness are — and how to store a graph in a computer.
- Why the path with the fewest edges need not be the shortest, and how BFS and Dijkstra deal with it.
- What a tree and a minimum spanning tree are, and why a neural network is an acyclic graph computed there and back.
Useful to know first: Sets and relations: the building blocks of definitions in AI
A map of cities and roads, a network of friends, the state space of a game, a neural network, and the computation in which a gradient is calculated — all of these are a graph: points connected by lines. Graphs are the most universal structure in computer science, and in artificial intelligence you meet them at every step. Trees are their simplest and most useful special case.
We build this whole part on a single graph with seven cities A to G and roads with lengths. Step by step we use it to show degrees, how to store a graph, shortest paths and the minimum spanning tree.
1. What a graph is
Definition — graph
Let V be a finite non-empty set; we call its elements vertices.
- An undirected graph is a pair G = (V, E), where E ⊆ {{u, v} : u, v ∈ V, u ≠ v}; the elements of E are edges — two-element subsets of V. Vertices u, v are adjacent if and only if {u, v} ∈ E.
- A directed graph is a pair G = (V, E), where E ⊆ V × V; an edge is an ordered pair (u, v) — an arrow from u to v. A directed graph is therefore a relation on V (see the part Sets and relations).
- A weighted graph is a triple G = (V, E, w), where (V, E) is a graph as in 1 or 2 and w : E → ℝ is a function that assigns each edge e ∈ E a weight w(e) (length, cost, time).
Unless stated otherwise, a graph in this part is undirected.
Vertices are “things”, edges are “relationships” between them. In an undirected graph the relationship holds in both directions (a road), in a directed one only in one (a one-way street, “follows on social media”). A weight is a number on an edge — how many kilometres, how much money, how many minutes.
2. Degree of a vertex
Definition — degree and the handshaking lemma
Let G = (V, E) be an undirected graph and v ∈ V. The degree of the vertex v is the number of edges that contain it (that leave it):
deg(v) = |{e ∈ E : v ∈ e}|.
Theorem (handshaking lemma). Let G = (V, E) be an undirected graph. Then
∑v ∈ V deg(v) = 2 |E|.
In particular, the sum of the degrees in every undirected graph is an even number.
Every edge has two ends, so when you add up how many edges leave each vertex, you count every edge exactly twice. That is why the sum of the degrees is always even.
The sum of the degrees is 2 + 4 + 4 + 4 + 4 + 4 + 2 = 24 and there are 12 edges, so 24 = 2 · 12 — exactly as the theorem says (colours as in the formula below). Degree matters in practice: in a social network it is the number of friends, on the web the number of links, and vertices with a high degree tend to be the most important ones.
∑v ∈ V deg(v) = 2 · |E|
- ∑v ∈ V
- we go through all vertices — counting the edges “from the vertices’ point of view”
- deg(v)
- at each vertex, the ends of the edges that touch it
- 2
- every edge {u, v} has two ends, so the sum meets it twice — once at u, once at v
- |E|
- the number of edges — the same count “from the edges’ point of view”
Theorem — the number of vertices of odd degree is even
Theorem. Let G = (V, E) be an undirected graph and L = {v ∈ V : deg(v) is odd} the set of its vertices of odd degree. Then |L| is an even number.
Proof. Split the sum of the degrees into vertices of even and of odd degree: ∑v ∈ V deg(v) = ∑v ∈ V ∖ L deg(v) + ∑v ∈ L deg(v). By the handshaking lemma the left-hand side is 2|E|, which is even; the first sum on the right is a sum of even numbers, hence even. So the second must be even too — and a sum of |L| odd numbers is even if and only if |L| is even. ∎
That is why you cannot draw a graph with five vertices each of which has degree 3: the sum 15 would be odd.
3. How to store a graph in a computer
A computer does not see a picture; it needs numbers. Two forms are common:
- Adjacency matrix — a |V| × |V| table; cell (u, v) holds the weight of the edge, or 0. A fast “is there an edge?”, but memory grows as |V|2.
- Adjacency list — for each vertex, a list of its neighbours. Memory grows only as |V| + |E|, which makes a huge difference for sparse graphs (a social network, a map).
Definition — adjacency matrix and adjacency list
Let G = (V, E, w) be a weighted undirected graph with non-zero weights (w(e) ≠ 0 for all e ∈ E) and n = |V| vertices, which we number: V = {v1, …, vn}. The adjacency matrix of the graph G is the square matrix A ∈ ℝn×n with entries (for i, j = 1, …, n)
Aij = w({vi, vj}) if {vi, vj} ∈ E; otherwise Aij = 0.
The weights must be non-zero so that an edge can be told apart from a missing edge. For an unweighted graph we write 1 instead of the weight. Since {vi, vj} = {vj, vi}, an undirected graph has Aij = Aji, that is A = AT.
For v ∈ V let N(v) denote the set of its neighbours:
N(v) = {u ∈ V : {u, v} ∈ E}.
The adjacency list is the mapping that assigns each vertex v ∈ V the set N(v), for a weighted graph together with the weights: {(u, w({u, v})) : u ∈ N(v)}. We have |N(v)| = deg(v).
Example — how much space the city graph and a road network take
The city graph: the matrix has 7 · 7 = 49 cells, of which only 24 are non-zero (each road twice, above and below the diagonal). The adjacency lists have ∑ deg(v) = 2 · 12 = 24 entries in total (colours as in the handshaking lemma above). Row B of the matrix is (4, 0, 5, 3, 7, 0, 0) — four non-zero numbers, because deg(B) = 4.
A road network with a million junctions, with 3 roads leaving each on average: |E| = 106 · 3/2 = 1.5 · 106. The matrix has (106)2 = 1012 cells, the lists only 2 · 1.5 · 106 = 3 · 106 entries — more than three hundred thousand times fewer.
The matrix is symmetric about the diagonal — the mark of an undirected graph. In AI the adjacency matrix is used by graph neural networks, which learn directly on graphs (molecules, social networks, road networks).
4. Paths, cycles and connectedness
Definition — path, cycle, connectedness
Let G = (V, E) be an undirected graph and u, v ∈ V.
- A path from u to v is a sequence of vertices (v0, v1, …, vk), k ≥ 0, such that v0 = u, vk = v, vi ≠ vj for i ≠ j, {vi−1, vi} ∈ E for i = 1, …, k. Its length is k (the number of edges); in a weighted graph (V, E, w) it is the sum of the weights ∑i=1k w({vi−1, vi}).
- A cycle is a sequence of vertices (v0, v1, …, vk) with k ≥ 3 in which v0, …, vk−1 are pairwise distinct, vk = v0 and {vi−1, vi} ∈ E for i = 1, …, k — a path that returns to its starting vertex after at least three edges.
- G is connected if and only if ∀u, v ∈ V there is a path from u to v.
- Define a relation ∼ on V: u ∼ v if and only if there is a path from u to v. It is an equivalence (reflexive thanks to the path of length 0, symmetric by reversing the path, transitive because a path can be chosen from the concatenation of two paths). Its equivalence classes are the connected components of G; they therefore form a partition of V (see the part Sets and relations).
A graph is therefore connected if and only if it has a single connected component.
A path is a route that never passes through the same place twice. A cycle is a loop. A connected graph is one where you can get from anywhere to anywhere; otherwise it falls apart into “islands” — components.
5. Shortest paths
The task “how do I get from A to G as quickly as possible” is a shortest path search — and that is exactly what the algorithms from the part on state space search did. But it depends on what we measure.
Definition — distance in a graph
Let G = (V, E, w) be a weighted undirected graph with non-negative weights, w : E → [0, ∞), and u, v ∈ V. For a path π let w(π) = ∑e ∈ π w(e) denote its length (the sum of the weights of its edges). The distance of the vertices u and v is
d(u, v) = min {w(π) : π is a path from u to v} if at least one such path exists; otherwise d(u, v) = ∞.
The minimum exists because a finite graph has finitely many paths. For an unweighted graph we take w(e) = 1 for all e ∈ E; the distance is then the smallest number of edges of a path from u to v.
d(u, v) = minπ : u → v ∑e ∈ π w(e)
- d(u, v)
- one number for a pair of vertices — what the algorithm is looking for
- minπ
- there are usually many paths from u to v; we want the best one, hence the minimum over all of them
- ∑e ∈ π
- the length of a path is made up of the edges that lie on it — we add them up
- w(e)
- the weight of one edge (kilometres); in BFS each one equals 1, and the sum then counts edges
If we care about the number of edges, breadth-first search is enough: first the neighbours of A, then their neighbours… The number above a vertex is its distance from A in edges:
from collections import deque
def bfs(sousede, start):
d = {start: 0}
fronta = deque([start])
while fronta:
u = fronta.popleft() # first come, first served
for v in sousede[u]:
if v not in d: # first visit = fewest edges
d[v] = d[u] + 1
fronta.append(v)
return d
From A we thus get the layers: B, C at distance 1; D, E, F at distance 2; G at distance 3. Each vertex is taken from the queue once and each edge is examined twice (from both ends), so BFS runs in time proportional to |V| + |E|.
Three edges lead to G (for example A–B–E–G). But if we count the length of the roads, we need Dijkstra’s algorithm — it always continues from the nearest vertex that has not been closed yet. The number above a vertex is now the shortest distance in kilometres, and the shortest path to G is highlighted:
The shortest path A–B–D–E–G has four edges, more than the three-edge path from BFS, but a length of only 12. The path A–B–E–G would measure 4 + 7 + 3 = 14 (colours as in the distance formula above). Fewer steps does not mean a shorter path — exactly the difference between BFS and UCS that we saw in the maze with mud.
Dijkstra’s algorithm step by step
For each vertex the algorithm keeps an estimate d[v] — the length of the best path found so far. At the start d[A] = 0 and ∞ everywhere else. Then it repeats: take the unclosed vertex with the smallest estimate, close it and try to use it to improve the estimates of its neighbours. This improvement is called edge relaxation:
d[v] ← min( d[v], d[u] + w(u, v) )
- d[v]
- the best length to v known so far; it stays if the new path is not better — the estimate never gets worse
- d[u]
- the length to the just-closed u — it is certainly the shortest by now, so we can build on it
- w(u, v)
- the last section from u to v; together with d[u] it is the length of the candidate path “via u”
import heapq
def dijkstra(sousede, start):
d = {v: float("inf") for v in sousede}
d[start] = 0
hotove = set()
halda = [(0, start)]
while halda:
du, u = heapq.heappop(halda) # unclosed vertex with the smallest d
if u in hotove:
continue
hotove.add(u) # d[u] is now final
for v, w in sousede[u]:
if du + w < d[v]: # relaxation of the edge (u, v)
d[v] = du + w
heapq.heappush(halda, (d[v], v))
return d
On the city graph from A the run looks like this. Each row shows the estimates after closing the vertex in the first column; the distances that are already final are in bold:
| step | closed | d[A] | d[B] | d[C] | d[D] | d[E] | d[F] | d[G] |
|---|---|---|---|---|---|---|---|---|
| 1 | A | 0 | 4 | 2 | ∞ | ∞ | ∞ | ∞ |
| 2 | C | 0 | 4 | 2 | 8 | ∞ | 10 | ∞ |
| 3 | B | 0 | 4 | 2 | 7 | 11 | 10 | ∞ |
| 4 | D | 0 | 4 | 2 | 7 | 9 | 10 | ∞ |
| 5 | E | 0 | 4 | 2 | 7 | 9 | 10 | 12 |
| 6 | F | 0 | 4 | 2 | 7 | 9 | 10 | 12 |
| 7 | G | 0 | 4 | 2 | 7 | 9 | 10 | 12 |
The colours match the terms of the relaxation above. In the third step the estimate of D improves from 8 (via C: 2 + 6) to 7 (via B: 4 + 3) and in the fourth the estimate of E from 11 (via B: 4 + 7) to 9 (via D: 7 + 2). G gets 9 + 3 = 12 and does not change any more: the path via F would measure 10 + 5 = 15.
Theorem — Dijkstra is correct for non-negative weights
Theorem. Let G = (V, E, w) be a weighted graph with non-negative weights, w : E → [0, ∞), start ∈ V the starting vertex and d[·] the estimates of Dijkstra’s algorithm run from the start (described above). Then for every vertex u, at the moment the algorithm closes it,
d[u] = d(start, u).
Why: every other path to u must leave the set of closed vertices for the first time somewhere, through a vertex x whose estimate is ≥ d[u] (otherwise we would have picked x, not u). The rest of the path from x to u has non-negative length, so the whole path is not shorter than d[u]. ∎
With a negative edge this argument breaks down — “the rest of the path” could make the length shorter. Negative weights therefore need a different algorithm (Bellman–Ford).
6. Trees
Definition — tree and rooted tree
Let G = (V, E) be an undirected graph.
- G is a forest if and only if it contains no cycle (each of its connected components is then a tree).
- G is a tree if and only if it is connected and contains no cycle.
Theorem. Let G = (V, E) be an undirected graph with n = |V| ≥ 1 vertices. Then the following statements are equivalent:
- G is a tree;
- G is connected and |E| = n − 1;
- G contains no cycle and |E| = n − 1;
- ∀u, v ∈ V there is exactly one path from u to v.
A rooted tree is a pair (T, r), where T = (V, E) is a tree and r ∈ V a marked vertex, the root. For v ∈ V:
- the depth h(v) is the length (number of edges) of the unique path from r to v; in particular h(r) = 0;
- the children of the vertex v are its neighbours in the direction away from the root, i.e. the vertices of the set {u ∈ N(v) : h(u) = h(v) + 1}; v is their parent;
- v is a leaf if and only if it has no child.
A tree is a graph with no loop at all — between two places there is always exactly one route. A family tree, folders on a disk, branching decisions. Remove a single edge and the tree falls apart; add one and a cycle appears.
In AI, trees are everywhere. A decision tree classifies with a series of questions from the root to a leaf. Search algorithms build a search tree — the BFS and DFS tree from the part on search is exactly that. And a chess program calculates a game tree, in which the vertices are positions and the edges are moves.
Theorem — a tree with n vertices has n − 1 edges (proof by induction)
Theorem. Let T = (V, E) be a tree with n = |V| ≥ 1 vertices. Then |E| = n − 1.
Lemma: let T be a tree with at least two vertices. Then T has a leaf, i.e. a vertex of degree 1. Proof of the lemma: take the longest path in the tree; its end vertex cannot have another neighbour off the path (the path could be extended) or on the path (a cycle would arise) — so it has degree 1.
Proof of the theorem by induction on n. Base case: a tree with 1 vertex has 0 edges. Inductive step: in a tree with n + 1 vertices remove a leaf together with its only edge. The rest is still connected and without cycles, hence a tree with n vertices, and by the induction hypothesis it has n − 1 edges. The original tree had one more, n. ∎
A search tree grows fast. If every vertex has b children (the branching factor), there are exactly bk vertices at depth k, and in the whole tree down to depth d:
N(b, d) = ∑k=0d bk = bd+1 − 1/b − 1
- N(b, d)
- how many vertices the search has to go through in the worst case — that is, how much time and memory it costs
- ∑k=0d
- we add level by level, from the root (k = 0) down to the deepest level d
- bk
- each vertex of level k − 1 has b children, so the count is multiplied by b with every level
- bd+1 − 1/b − 1
- the sum of a geometric series in closed form (for b ≥ 2); it shows that the last level outweighs all the previous ones combined
7. Minimum spanning tree
Definition — spanning tree and Kruskal’s algorithm
Let G = (V, E, w) be a connected weighted undirected graph.
- A spanning tree of the graph G is a graph T = (V, F) with F ⊆ E that is a tree — it contains all vertices of G and only some of its edges.
- The weight of a spanning tree is w(T) = ∑e ∈ F w(e).
- A spanning tree T is minimum if and only if w(T) ≤ w(T′) for every spanning tree T′ of the graph G.
Kruskal’s algorithm.
- Input: a connected weighted undirected graph G = (V, E, w) with m = |E| edges.
- Output: a set of edges F ⊆ E such that (V, F) is a minimum spanning tree of G.
- Sort the edges by weight in ascending order: e1, …, em with w(e1) ≤ … ≤ w(em).
- Set F := ∅.
- For i = 1, …, m: if the graph (V, F ∪ {ei}) contains no cycle, set F := F ∪ {ei}; otherwise skip the edge ei.
- Return F.
Termination: the algorithm stops after going through all m edges (it may stop earlier, as soon as |F| = |V| − 1). It is a greedy algorithm — at every step it takes the lightest admissible edge and never revises the decision — and yet it always finds a minimum spanning tree (theorem below).
You want to connect all the cities with electric lines as cheaply as possible. It is enough that you can get from anywhere to anywhere — loops are unnecessary. You take the shortest sections first and skip the ones that would close a loop.
The spanning tree has 6 edges for 7 vertices — exactly n − 1, as the theorem on trees says — and a total length of 18. The algorithm rejected the six remaining roads because they would have created a cycle.
Example — Kruskal on the city graph edge by edge
The edges sorted by length (accepted ones in bold): A–C (2), D–E (2), B–D (3), E–G (3), A–B (4), D–F (4), B–C (5), F–G (5), C–D (6), E–F (6), B–E (7), C–F (8).
The first six edges are accepted: A–C and D–E join pairs, B–D adds B to D–E, E–G adds G and A–B connects the group {A, C} with the group {B, D, E, G}. D–F attaches the last vertex F. Now all vertices are in a single component, so every further edge would join two vertices of the same component — it would close a cycle and the algorithm rejects it.
Length of the spanning tree: 2 + 2 + 3 + 3 + 4 + 4 = 18.
def kruskal(vrcholy, hrany):
rodic = {v: v for v in vrcholy} # each vertex is on its own for now
def koren(v): # representative of the component v lies in
while rodic[v] != v:
v = rodic[v]
return v
kostra = []
for u, v, w in sorted(hrany, key=lambda h: h[2]):
ku, kv = koren(u), koren(v)
if ku == kv:
continue # u and v are already connected: the edge would close a cycle
rodic[ku] = kv # merge two components
kostra.append((u, v, w))
return kostra
Theorem — why the greedy approach works (the cut property)
Let G = (V, E, w) be a connected weighted undirected graph. A cut is a division of the vertices into two non-empty parts S and V ∖ S, where ∅ ≠ S ⊊ V. An edge {u, v} ∈ E crosses the cut if and only if |{u, v} ∩ S| = 1 (one end in S, the other outside).
Theorem. Let (S, V ∖ S) be a cut of the graph G and e an edge that crosses the cut and has the smallest weight of all edges crossing this cut. Then there is a minimum spanning tree of G that contains the edge e.
Proof: take any minimum spanning tree T; if it contains e, we are done. Otherwise consider T without e. Adding e creates a cycle, and that cycle must cross the cut once more, through some edge f. Removing f gives a spanning tree again, with weight w(T) + w(e) − w(f) ≤ w(T), because w(e) ≤ w(f). So it is also minimum and contains e. ∎
Kruskal accepts an edge only when it joins two different components — and it is the lightest edge across the cut “one of those components against the rest”, because it has already processed all the lighter ones.
8. Acyclic graphs and the computation of a neural network
Definition — DAG and topological ordering
Let G = (V, E) be a directed graph, E ⊆ V × V, with n = |V| vertices.
- A directed cycle is a sequence of vertices (v0, v1, …, vk), k ≥ 1, such that (vi−1, vi) ∈ E for i = 1, …, k and vk = v0 — following the arrows you can return to the starting vertex.
- G is a directed acyclic graph (DAG) if and only if it contains no directed cycle.
- A topological ordering of the graph G is a bijection π : V → {1, …, n} (an order of the vertices) such that ∀(u, v) ∈ E : π(u) < π(v), i.e. every edge goes from left to right — u comes before v in the order.
Theorem. Let G = (V, E) be a directed graph. Then G has a topological ordering if and only if it is acyclic.
A DAG is a graph of dependencies in which nothing goes round in a circle: first put on your socks, then your shoes. A topological ordering is an order in which everything can be done so that each step has ready what it depends on.
This is how every neural network computes. Here is the computation of a single neuron ŷ = σ(w · x + b) and its loss L(ŷ, y) as a computation graph: inputs on the left, operations as vertices, arrows showing what depends on what. The numbers are the topological order:
The network computes forward in topological order — first the product, then the sum, the sigmoid and the loss. And when it then learns, it goes through the same graph backwards: backpropagation of the error visits the vertices in reverse topological order and applies the chain rule at each one. Libraries like PyTorch build this graph themselves on every computation. Incidentally, the graph of module prerequisites in the syllabus of this series is a DAG too.
How to find a topological order
The in-degree of a vertex v of a directed graph (V, E), deg−(v) = |{u ∈ V : (u, v) ∈ E}|, is the number of arrows that lead into v — the number of things v depends on. Kahn’s algorithm repeatedly takes a vertex that is no longer waiting for anything:
from collections import deque
def topologicke(vrcholy, hrany):
vstupni = {v: 0 for v in vrcholy}
for u, v in hrany:
vstupni[v] += 1
fronta = deque(v for v in vrcholy if vstupni[v] == 0) # inputs: depend on nothing
poradi = []
while fronta:
u = fronta.popleft()
poradi.append(u)
for a, b in hrany:
if a == u:
vstupni[b] -= 1 # u is done, b waits for one thing less
if vstupni[b] == 0:
fronta.append(b)
return poradi if len(poradi) == len(vrcholy) else None # None: the graph has a cycle
On the neuron graph this gives the order x, w, b, y, ·, +, σ, L: first the four inputs, then the product, the sum, the sigmoid and the loss. When a graph has a cycle, the vertices on the cycle wait for each other, their in-degree never drops to zero and they never get into the order — hence the last line.
Example — a pass through the neuron graph there and back
Inputs x = 2, w = 0.5, b = −1, correct answer y = 1, loss L = (ŷ − y)2, σ(z) = 1/1 + e−z.
Forward (in topological order): w · x = 1; z = 1 + (−1) = 0; ŷ = σ(0) = 0.5; L = (0.5 − 1)2 = 0.25.
Backward (in reverse order; colours as in the breakdown of the chain rule below): ∂L/∂ŷ = 2(ŷ − y) = −1; ∂ŷ/∂z = σ(z)(1 − σ(z)) = 0.25; ∂L/∂z = −1 · 0.25 = −0.25; ∂L/∂b = ∂L/∂z · 1 = −0.25; ∂L/∂w = ∂L/∂z · ∂z/∂w = −0.25 · 2 = −0.5 (∂z/∂w = x = 2).
Both derivatives are negative: increasing w and b decreases the loss — the network moves towards the answer 1.
∂L/∂w = ∂L/∂ŷ · ∂ŷ/∂z · ∂z/∂w
- ∂L/∂w
- how sensitively the loss reacts to the weight — this decides how the weight moves during learning
- ∂L/∂ŷ
- the edge σ → L: how much the loss changes when the output changes; it is computed first because L is last in the order
- ∂ŷ/∂z
- the edge + → σ: how the sigmoid passes on a change of its input
- ∂z/∂w
- the edges w → · → +: the change of the sum per unit of weight, that is x
9. Graphs in artificial intelligence
- A state space is a graph: states are vertices, actions are edges with a cost. Search is finding a path in a graph.
- The computation graphs of neural networks are DAGs; training is a pass there and back.
- Knowledge graphs store facts as edges such as “Prague — is the capital of — Czechia”, and search engines assemble answers from them.
- Bayesian networks are DAGs of probabilistic dependencies — we will get to them in the module on probabilistic models.
- Graph neural networks learn directly on graphs: they predict the properties of molecules, traffic or recommendations.
10. Summary
- A graph is a set of vertices and edges; edges can have a direction and a weight. The sum of the degrees is twice the number of edges.
- A graph is stored as an adjacency matrix or as an adjacency list — the latter is much more economical for sparse graphs.
- BFS finds the path with the fewest edges, Dijkstra the shortest one by weights — and they need not be the same.
- A tree is a connected graph without cycles with n − 1 edges; the greedy Kruskal’s algorithm finds a minimum spanning tree.
- A neural network is a computational DAG: the forward pass runs in topological order, the gradient runs backwards.
Do you see it differently? Write to support@coden-app.com.