Declaring a graph and searching it
A graph is a model. Write its nodes and edges with what you know about them, inherit every algorithm, and call them by name.
1. Declare the graph
open Prelude.Graphs
model Roads : Graph {
node home { x = 0, y = 0, population = 1200, label = "Home" }
node park { x = 1, y = 1, label = "Central Park" }
node shop { x = 2, y = 0, label = "Market" }
node office { x = 6, y = 0 }
edge home → shop { length = 4, time = 7, toll = 0, capacity = 30, road = "A1" }
edge home → park { length = 2, time = 3, capacity = 10 }
edge park ↔ shop { length = 1, time = 2, capacity = 10 }
edge shop → office { length = 5, time = 6, toll = 2, capacity = 20 }
}
→ (or ->) is one direction, ↔ (or <->) both. An attribute is a number or a quoted text; the braces are optional.
The nodes are numbered in the order the model first names them: home 0, park 1, shop 2, office 3.
2. Say what a path costs, and how far a place looks
def cost(edges) ≔ time(edges) + 2 · toll(edges)
def heuristic(v) ≔ distanceTo(v, office)
time(edges) is the time of every edge at once, 0 where an edge does not say; cost is what every path algorithm
minimises (without it, length, and without that, 1 per edge). distanceTo(v, office) is the straight line from every
place to the office, over the node attributes x and y. Write edges, not e: e is Euler’s number.
3. Call it from C#
var g = new Roads();
g.Path("home", "office"); // home, park, shop, office — cost 15
g.Path("home", "office", by: "length"); // the same route, length 8
g.Path("home", "office", by: "toll"); // home, shop, office
g.Node("park").Label; // "Central Park"
g.Edge("home", "shop").Road; // "A1"
g.MaxFlow("home", "office").Value; // 20 — the office road is full
g.Attribute("population"); // [1200, 0, 0, 0]
Every answer here is asserted by GraphSampleCase. Numbers in a record are double?: g.Edge("home", "shop").Toll is
0, g.Edge("home", "park").Toll is null. Each method also takes node indices: g.Path(0, 3).
An attribute an edge does not declare is two different answers: 0 in a formula, null in C#. by: names a numeric
edge attribute — by: "label" is an ArgumentException listing the ones that are numbers.
4. A* and its estimate
The heuristic names its goal. On the Sample’s twelve-place Town, the straight line closes 4 places where the same
roads without a map close 12, for the same route of 8
(GraphSampleCase.A_straight_line_estimate_reaches_the_tower_closing_four_places_of_twelve). A* is guaranteed cheapest
only while no edge costs less than its straight line under the weighting searched — true of Roads under its cost,
not under length. Strictly, the estimate must be consistent (\(h(u) \le C_{uv} + h(v)\)), not merely admissible:
the goal closes the search and a closed node is never reopened. def pathWeight ≔ 0 makes the same search greedy
best-first.
5. Pick an algorithm
| Question | Method |
|---|---|
| cheapest distances and routes | Dijkstra, Path |
| cheapest route with an estimate | AStar |
| negative weights, negative cycles | BellmanFord |
| fewest hops; the order a search meets places | Bfs, Dfs |
| an order for tasks; when each can start | Topological, Longest, CriticalPath |
| the cheapest network joining everything | SpanningTree, Prim |
| how much gets through, and what limits it | MaxFlow |
| who matters | Closeness, Betweenness, Degree, Eigenvector, PageRank |
6. What the answers promise
Every tie goes to the lowest node index, so an answer is a function of the graph alone — but that also means a
breadth-first parent is the lowest-indexed node of the frontier reaching it, not the first in a FIFO queue. Distances
are sums, so every comparison tolerates rounding at a relative \(10^{-12}\): weights below that are one flat tie, and a
negative cycle lighter than that is not flagged. Eigenvector answers NaN rather than a number power iteration has
not settled on (raise iterations). Betweenness counts ordered pairs, unnormalised, endpoints excluded — halve it for
an undirected graph. Closeness and Degree answer what networkx answers, including at \(n = 1\). The full list is in
the Graphs reference.
Two names to keep clear of: a graph’s own def may not take a Prelude name its inherited algorithms reach (positions,
say — the build stops with HB0001), and a node may not be called adjacency, nodeTable, edgeTable, e, pi, or
the same as one of the graph’s defs.
The build says what is wrong in the graph’s own words: edges without : Graph, an attribute that is a number on one
node and text on another, a formula reading a text attribute, a cost reading an attribute no edge has, distanceTo
without x and y.