{
  "aliases": null,
  "backlinks": [
    {
      "field": "uses",
      "target": "4135XQ4WHK"
    }
  ],
  "body": "\n## Statement\n\nLet $A$ be a [[symmetric|0VR671PHE5]] $n \\times n$ matrix.\nIts [[graph|00C0BR7D7H]] $G$ has vertices $1, \\dots, n$ and an edge between $i \\ne j$ when $a_{ij} \\ne 0$; assume $G$ is connected.\nThe *bandwidth* of $A$ is $\\max \\set{\\abs{i - j} : a_{ij} \\ne 0}$.\nThe *Cuthill–McKee algorithm* orders the vertices as follows.\nIt picks a start vertex $v_1$.\nFor $k = 1, 2, \\dots$ it appends to the list the neighbours of $v_k$ not yet listed, in order of increasing [[degree|0KS0KRDV4Y]].\nLet $L_0 = \\set{v_1}$ and, for $d \\ge 1$, let $L_d$ be the set of vertices at distance $d$ from $v_1$ in $G$.\nThen:\n\n1. the algorithm lists every vertex exactly once, and each level $L_d$ forms a contiguous block of the list, in the order $L_0, L_1, L_2, \\dots$;\n2. if $P$ is the [[permutation matrix|08SP3DF8NB]] of this ordering, the bandwidth of $P A P^T$ is at most $\\max_d \\big(\\abs{L_d} + \\abs{L_{d+1}}\\big) - 1$;\n3. the reversed ordering, called *reverse Cuthill–McKee*, gives a matrix with the same bandwidth.\n\n## Remarks\n\nThe list is built exactly as a breadth-first search from $v_1$ would build its queue, which lists the vertices by nondecreasing distance from $v_1$; this gives clause 1.\nIn a breadth-first level structure, every edge joins two vertices of the same level or of adjacent levels.\nTwo adjacent levels occupy $\\abs{L_d} + \\abs{L_{d+1}}$ consecutive positions, so the positions of the ends of an edge differ by at most $\\abs{L_d} + \\abs{L_{d+1}} - 1$; this gives clause 2.\nClause 3 holds because reversing the order maps the positions $p, q$ to $n + 1 - p, n + 1 - q$, which have the same difference.\nSo a start vertex with many small levels, such as a vertex far from the rest of the graph, gives a narrow [[band|Z58FRZCF8P]].\nIn practice one starts from a vertex of minimum degree or a pseudo-peripheral vertex.\nExample: for the path graph $2 - 1 - 3$ (with $a_{12}, a_{13} \\ne 0$), starting at $v_1 = 2$ gives the order $2, 1, 3$, and the reordered matrix is tridiagonal, with bandwidth $1$.\nThe reverse ordering usually produces less fill-in in a [[Cholesky factorization|0WKG8CYY6A]], which is why it is the version used in sparse solvers.\n\n## Explanations\n\n### L1 human\n\nA [[sparse matrix|JGACZYEEY7]] is easier to factor when its nonzero entries sit close to the diagonal.\nThe Cuthill–McKee algorithm renumbers the unknowns so that this happens.\nIt starts at one unknown and numbers its neighbours, then their neighbours, and so on, layer by layer, like ripples spreading on a pond.\n\n### L2 human\n\nThe algorithm is a heuristic: it does not find the smallest possible bandwidth, which is an NP-hard problem, but it is fast and usually good.\nIt runs in time roughly proportional to the number of nonzero entries, up to the sorting by degree.\nReverse Cuthill–McKee is a standard preprocessing step before banded or envelope Cholesky factorization of symmetric sparse matrices.\n",
  "commit": "ff8a40749dc16545e3d2fc637f6b0196e81d0bfa",
  "front": {
    "about": [
      "JGACZYEEY7"
    ],
    "kind": "statement",
    "msc": [
      "65F50",
      "05C85"
    ],
    "name": "Cuthill–McKee algorithm",
    "role": "proposition",
    "same_as": {
      "wikidata": "Q1146458",
      "wikipedia": "Cuthill–McKee algorithm"
    },
    "sources": [
      {
        "url": "https://en.wikipedia.org/wiki/Cuthill–McKee_algorithm"
      }
    ],
    "tag": "1X0E3JHCH9",
    "uses": [
      "JGACZYEEY7",
      "Z58FRZCF8P",
      "0VR671PHE5",
      "00C0BR7D7H",
      "0KS0KRDV4Y",
      "08SP3DF8NB",
      "0WKG8CYY6A"
    ]
  },
  "kind": "statement",
  "link": "https://tamnd.github.io/math2/node/1X0E3JHCH9/",
  "links": [
    {
      "field": "about",
      "target": "JGACZYEEY7"
    },
    {
      "field": "uses",
      "target": "JGACZYEEY7"
    },
    {
      "field": "uses",
      "target": "Z58FRZCF8P"
    },
    {
      "field": "uses",
      "target": "0VR671PHE5"
    },
    {
      "field": "uses",
      "target": "00C0BR7D7H"
    },
    {
      "field": "uses",
      "target": "0KS0KRDV4Y"
    },
    {
      "field": "uses",
      "target": "08SP3DF8NB"
    },
    {
      "field": "uses",
      "target": "0WKG8CYY6A"
    }
  ],
  "markdown": "https://tamnd.github.io/math2/node/1X0E3JHCH9.md",
  "msc": [
    "65F50",
    "05C85"
  ],
  "name": "Cuthill–McKee algorithm",
  "prov": null,
  "role": "proposition",
  "source": "https://github.com/tamnd/math2/blob/main/nodes/1X0/1X0E3JHCH9.md",
  "status": null,
  "tag": "1X0E3JHCH9",
  "uri": "m2://1X0E3JHCH9",
  "url": "https://tamnd.github.io/math2/wiki/cuthill-mckee-algorithm/",
  "writing": {
    "tag": "1X0E3JHCH9",
    "kind": "statement",
    "level": "W0",
    "next": [
      {
        "what": "an inventory row",
        "note": "the row of the inventory that the node accounts for",
        "have": 0,
        "want": 1
      },
      {
        "what": "a source with a locator",
        "have": 0,
        "want": 1
      }
    ]
  }
}
