Memra

Collecting solutions: findall, setof, and minimum-cost paths

Use findall/3 and setof/3 to gather all solutions, then build a minimum-cost path over weighted edges (the A1 setof task) — the standard collect-all-then-pick-best pattern.

Backtracking finds one solution at a time

A bare Prolog query yields solutions one at a time on backtracking. To reason about *all* solutions at once — count them, sort them, pick the cheapest — you need a meta-predicate that collects them into a list. The two you must know:

- findall(Template, Goal, List) — runs Goal exhaustively and collects every instantiation of Template into List. Keeps duplicates, preserves solution order, and returns [] if Goal never succeeds. - setof(Template, Goal, List) — like findall but the result is sorted and duplicate-free (it is a *set*). Crucially, sorting on a compound term like [Cost, Path] sorts by Cost first — which is how you find a minimum.

The collect-all-then-pick-best pattern

Optimisation in Prolog is usually two moves: (1) enumerate every candidate with findall/setof, then (2) pick the best. For a minimum-cost path (the A1 min_path task), weight the edges and collect [Cost, Path] pairs; because setof sorts ascending, the head of the sorted list is the cheapest.

Worked example — minimum-cost path (A1)

edge(a, b, 3). edge(b, c, 1). edge(c, d, 2). edge(b, d, 5).

path(G, G, _, [G], 0).
path(N, G, V, [N | P], Cost) :-
    edge(N, Nx, W), \+ member(Nx, V),
    path(Nx, G, [Nx | V], P, C1), Cost is W + C1.

min_path(S, G, Path, Cost) :-
    setof([C, P], path(S, G, [S], P, C), [[Cost, Path] | _]).

The path/5 predicate is the acyclic finder from the previous lesson, now also threading a running cost (each step adds its edge weight W). min_path calls setof to gather every [Cost, Path] pair; setof sorts them ascending by cost, and the pattern [[Cost, Path] | _] peels off the head — the minimum.

For this graph the candidate paths from a to d are a→b→c→d (cost 3+1+2 = 6) and a→b→d (cost 3+5 = 8). setof sorts to [[6, [a,b,c,d]], [8, [a,b,d]]], so min_path returns the cost-6 route. The Python exercise enumerates the same paths and takes the minimum by cost.

NORMAL ~/memra/learn/comp-456/findall-setof-min-cost-path utf-8 LF