Hi! @cvvergara @robe,
I have a design question about pgr_coreNumbers.
The standard definition of the k-core is stated for simple graphs:
- the k-core is the maximal subgraph in which every vertex has degree ≥ k
- the core number of a vertex is the largest k for which it belongs to the k-core
- on n vertices the maximum possible core number is n - 1 (the complete graph Kₙ)
In my current implementation the initial degree comes straight from src/metrics/coreNumbers.cpp:
degree[*vi] = boost::out_degree(*vi, graph.graph);
Since pgrouting::UndirectedGraph is a multigraph, out_degree counts every parallel edge separately and counts a self-loop twice. So the peeling operates on multigraph degrees, not simple-graph degrees.
While adding degenerate-input pgTAP tests for week 8 I measured what this produces:
- one edge
1-2→1:1 2:1 - two parallel edges
1-2→1:2 2:2 - three parallel edges
1-2→1:3 2:3 - a single self-loop
1-1→1:2 - self-loop
1-1plus edge1-2→1:2 2:1
However, two of these are not reachable under the simple-graph definition:
- three parallel edges between two vertices report core 3, but on two vertices the maximum possible core number is 1
- a lone self-loop reports core 2, but that vertex has no neighbours at all and would be core 0
Also, in the existing pgRouting codebase this behaviour already has a precedent. pgr_degree - a released, non-experimental function in the same family reports exactly the same degrees on the same inputs:
- two parallel edges
1-2→pgr_degreegives1:2 2:2,pgr_coreNumbersgives1:2 2:2 - three parallel edges
1-2→pgr_degreegives1:3 2:3,pgr_coreNumbersgives1:3 2:3 - a single self-loop
1-1→pgr_degreegives1:2,pgr_coreNumbersgives1:2
So pgr_coreNumbers is already consistent with pgr_degree; it is not introducing a new convention.
This leaves me unsure which approach to follow:
Option A (Matches pgr_degree): keep multigraph degrees as they are, and document the consequence explicitly in pgr_coreNumbers.rst- that core numbers scale with edge multiplicity, so users importing road networks with duplicate geometry may see inflated cores. This keeps the metrics family internally consistent.
Option B (Match the textbook definition): collapse parallel edges and drop self-loops before peeling, so pgr_coreNumbers always reports simple-graph core numbers. This matches the published definition and the values users would compute by hand, but makes pgr_coreNumbers and pgr_degree disagree on the same input.
My pgTAP tests currently pin the existing (Option A) behaviour, so they document what the function does today - I can flip them if Option B is preferred.
Which approach would you prefer?
thank you
sakirr